openapi: 3.2.0
info:
  title: 'Voxbi Cockpit API'
  version: 0.1.0
  x-logo:
    url: logos/Voxbi_Cockpit_Logo_RGB.svg
    altText: 'Voxbi Logo'
  description: |
    REST API for the Voxbi Cockpit PBX platform. Use it to manage users, extensions, SIP devices, phone numbers, call flows, IVRs, queues, schedules, and related telephony resources.

    All resources are scoped to a PBX tenant. The authenticated identity determines which PBX(es) you can access.

    Every request must be authenticated. See **Authentication** for the available schemes.

    ## Principal-conditional fields

    Most resources are reachable by two kinds of token: a **user-owned** token
    (the cockpit/mobile Bearer token) and a **PBX-owned API key** (created on the
    Integrations page). A few response fields are *per-user* and therefore depend
    on which kind of token you use: they are returned for user-owned tokens and
    **omitted entirely** for PBX API-key tokens (a PBX has no per-user state).
    Such fields are flagged **PRINCIPAL-CONDITIONAL** in their description -
    examples: `is_favorite` on extensions and contacts, and `editable` on contacts.

    ## Embedding related resources

    List and detail endpoints accept an `?include=` query parameter: a
    comma-separated list of related resources to embed. Each endpoint documents
    its own allowed values; anything not in that allow-list is rejected, and
    nothing is embedded unless you ask for it.

    Some relations are **dot-nested**, which lets you choose how deep to go. For
    example, on an extension you can request `user` to embed just the user, or
    `user.groups` to embed the user **and** its groups (you do not have to load
    the parent separately). Combine several with commas, e.g.
    `?include=user.groups,sipDevice`.

    ## Rate limiting

    Requests are rate limited per API key (per PBX). The default budget is 120
    requests per minute; it may be higher depending on your plan. Every response
    reports your current budget so you do not have to hard-code the number:

    - `X-RateLimit-Limit` - the limit applied to this request
    - `X-RateLimit-Remaining` - requests left in the current window

    When you exceed the limit the API responds with `429 Too Many Requests` and a
    `Retry-After` header (seconds to wait before retrying). Always read these
    headers rather than assuming a fixed rate: the budget can change per plan, and
    a few endpoints have their own stricter limit. The clearest example is
    **Push the PBX configuration**, which is capped at 1 request per minute - that
    endpoint documents its own limit and `429` response.
  termsOfService: 'https://www.voxbi.com/legal'
  contact:
    name: 'Voxbi Cockpit API Support'
    url: 'https://www.voxbi.com/contact'
    email: team-voxbi@mixvoip.com
  license:
    name: Proprietary
    url: 'https://www.voxbi.com/legal'
servers:
  -
    url: 'https://cockpit.voxbi.com/api/v1'
    description: 'The production API server'
  -
    url: 'https://staging-cockpit.voxbi.com/api/v1'
    description: 'The staging API server'
  -
    url: 'https://dev-cockpit.voxbi.com/api/v1'
    description: 'The development API server'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: 'Bearer <token>'
      description: |-
        **User bearer token.** Default authentication for customer-facing endpoints.
        Obtain a token by calling `POST /login` with your credentials, then send it
        on every subsequent request as `Authorization: Bearer <token>`. The token
        inherits the permissions and PBX scope of the authenticated user.
    ApiKeyAuth:
      type: apiKey
      name: Authorization
      in: header
      x-internal: true
    PbxServerAuth:
      type: http
      scheme: bearer
      bearerFormat: 'Bearer <token>'
      description: 'Auth for Pbx server'
      x-internal: true
    PbxApiKey:
      type: http
      scheme: bearer
      bearerFormat: 'Bearer <pbx_api_key>'
      description: "PBX API key, used by the customer's PBX server (e.g. for roaming login/logout)"
    IntegrationApiKey:
      type: http
      scheme: bearer
      description: |
        API key created on the Cockpit **Integrations** page (an "API key" integration).
        It is a bearer token owned by the customer's PBX and limited to the scopes
        selected when the key was created (e.g. `phone-numbers`, `push-configuration`).

        Send it in the `Authorization` header:

        ```
        Authorization: Bearer <api_key>
        ```

        Manage keys (create / reveal / revoke) from **Integrations → New integration →
        API key**.
  schemas:
    Twinning:
      type: object
      description: |
        Twinning: an external destination that rings alongside a user's extension
        (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
        the twinned destination rings in parallel so the call can be answered away
        from the desk phone. Tenant scoping is derived from the attached user; this
        resource has no direct `pbx_id` column of its own.
      required:
        - id
        - user_id
        - status
        - phone_number
        - delay
        - sync_source
        - type
        - dial_strategy
        - fmc_enabled
        - backup_phone_number
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the twinning.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        user_id:
          type: string
          format: uuid
          description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
          example: 550e8400-e29b-41d4-a716-446655440001
        status:
          type: string
          enum:
            - enabled
            - disabled
          description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
          example: enabled
        phone_number:
          type:
            - string
            - 'null'
          description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
          example: '+12125550100'
        delay:
          type: integer
          format: int32
          minimum: 0
          description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
          example: 5
        sync_source:
          type: string
          enum:
            - manual
            - provision
            - legacy_import
          description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
          example: manual
        type:
          type: string
          enum:
            - mobile
            - teams
          description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
          example: mobile
        dial_strategy:
          type: string
          enum:
            - gsm_only
            - voip_only
            - voip_and_gsm_fallback
          description: |
            How the mobile leg is dialed: `gsm_only` uses the cellular network only,
            `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
            VoIP first and falls back to GSM. Only meaningful for mobile-type
            twinnings that use the Fixed-Mobile Convergence (FMC) integration.
          example: voip_and_gsm_fallback
        fmc_enabled:
          type: boolean
          description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
          example: false
        backup_phone_number:
          type:
            - string
            - 'null'
          description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
          example: '+12125550101'
        created_at:
          type:
            - string
            - 'null'
          format: date-time
          description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
          example: '2024-03-01T08:29:07Z'
          readOnly: true
        updated_at:
          type:
            - string
            - 'null'
          format: date-time
          description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
          example: '2024-03-01T08:29:07Z'
          readOnly: true
    InCallState:
      type: object
      description: |
        A user's live "on a call right now" flag, owned by Cockpit and reported by the
        client itself (`POST /in-call`).

        The flag is deliberately short-lived: a `true` is trusted for `ttl_seconds` only
        (one hour by default) and then decays back to `false`, so a client that never
        reports the hang-up cannot leave the user marked in-call indefinitely. Reading a
        user who has reported nothing inside that window is not an error: it presents as
        `in_call: false` with null timestamps.
      required:
        - user_id
        - in_call
        - in_call_updated_at
        - expires_at
        - ttl_seconds
      properties:
        user_id:
          type: string
          format: uuid
          description: "The user the flag belongs to (always the bearer token's own user)."
          example: 550e8400-e29b-41d4-a716-446655440000
        in_call:
          type: boolean
          description: 'Whether the user is currently reported as being on a call.'
          example: true
        in_call_updated_at:
          type:
            - string
            - 'null'
          format: date-time
          description: 'When the flag was last reported, or null if nothing was reported inside the window.'
          example: '2026-08-03T09:14:22+00:00'
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            When the current value stops being trusted and reverts to false, or null when there
            is no live value. Refreshed on every report.
          example: '2026-08-03T10:14:22+00:00'
        ttl_seconds:
          type: integer
          description: 'How long (seconds) a reported flag is trusted before it decays to false.'
          example: 3600
    TempusTransaction:
      type: object
      description: |
        Absence request as serialized by the V1 `TempusTransactionResource`. Backed by
        a single `TempusTransaction` ledger row, this object represents an employee
        absence (legal holiday, home office, illness, special leave, overtime balance)
        together with its approval status and requested period.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Several values are remapped from internal storage to the API
        contract: the internal `approved`, `rejected`, and `cancelled` statuses are
        exposed as `accepted`, `rejected`, and `canceled`; the internal `absence` type
        is exposed as `legal`. Other status and type values pass through unchanged.

        `employee_id` is the canonical id of the employee the request belongs to.
        Several identifier fields are intentionally redundant for client convenience:
        `requester_id` and `creator_id` both return that same employee id, and
        `absence_request_id` mirrors `id`. `ext_id` is a different value - the
        employee's extension id (see below). `holiday_id` is reserved for future use
        and is always null.
      required:
        - id
        - mxvp_user_id
        - employee_id
        - requester_id
        - creator_id
        - ext_id
        - company_id
        - absence_request_id
        - holiday_id
        - status
        - type
        - sub_type
        - start
        - end
        - requested_time
        - working_days
        - total_seconds
        - workshift_seconds_per_day
        - is_half_day
        - starts_half_day
        - ends_half_day
        - start_time
        - end_time
        - working_day_details
        - comment
        - accepted_by
        - created
        - modified
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique absence request (transaction) identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this absence request. Mirrors the
            transaction's `pbx_id`. Null for records not bound to a specific tenant.
          example: 550e8400-e29b-41d4-a716-446655440001
        employee_id:
          type: string
          format: uuid
          description: |
            Canonical identifier of the Tempus employee this request belongs to. This
            is the value the `filter[employee_id]` query parameter matches against.
          example: 550e8400-e29b-41d4-a716-446655440002
        requester_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus employee the absence belongs to. Returns the same
            value as `employee_id` and `creator_id`.
          example: 550e8400-e29b-41d4-a716-446655440002
        creator_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus employee who owns the absence. Returns the same
            value as `requester_id` (the owning employee, not the acting principal).
          example: 550e8400-e29b-41d4-a716-446655440002
        ext_id:
          type:
            - string
            - 'null'
          description: |
            External system identifier of the employee, resolved from the linked
            employee record. Null when the employee has no external mapping.
          example: EXT-10293
        company_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus company the absence is attributed to. Null when
            the request is not scoped to a specific company.
          example: 550e8400-e29b-41d4-a716-446655440003
        absence_request_id:
          type: string
          format: uuid
          description: |
            Alias of `id`, provided for clients that reference absence requests by this
            field name. Always equal to `id`.
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        holiday_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Reserved for a future link to a public-holiday record. Always null in the
            current API version.
          example: null
        status:
          type:
            - string
            - 'null'
          enum:
            - pending
            - accepted
            - rejected
            - canceled
            - pending_removal
            - removed
          description: |
            Approval status of the absence request, remapped for the API: internal
            `approved` is returned as `accepted` and internal `cancelled` as `canceled`.
            `pending` awaits validation, `pending_removal` and `removed` track removal
            of a previously approved absence. Null only for records with no status set.
          example: pending
        type:
          type: string
          enum:
            - legal
            - home_office
            - illness
            - special
            - overtime_balance
          description: |
            Category of the absence. The internal `absence` type is remapped to `legal`
            (legal holiday). `home_office` is a remote-work day, `illness` is sick
            leave, `special` is special leave, and `overtime_balance` is an
            overtime-balance adjustment.
          example: legal
        sub_type:
          type:
            - string
            - 'null'
          description: |
            Optional sub-classification of the absence (for example `removal` for a
            removal request, or a computed/rollover marker for ledger adjustments).
            Null when the request carries no sub-type.
          example: removal
        start:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Start of the absence period as an ISO 8601 timestamp. Null when the request
            has no start date.
          example: '2024-03-01T00:00:00+00:00'
        end:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            End of the absence period as an ISO 8601 timestamp. Null when the request
            has no end date.
          example: '2024-03-05T00:00:00+00:00'
        requested_time:
          type:
            - object
            - 'null'
          description: |
            Per-day breakdown of the requested time, stored as a map of date strings to
            durations in seconds. Used to compute the effective amount while the request
            is pending. Null when no per-day breakdown was supplied.

            Seconds are the employee's own scheduled day, not a nominal 8h: a part-timer on
            a 4h day books `14400` for a full day off, and a half of that day is `7200`.
            Only working days appear: a weekend, public holiday or company special holiday
            inside the range is omitted.

            Rows written before that was true carry a `0` entry for each such day, and rows
            created over this API before it carried a flat `28800` regardless of shift. So
            do **not** count these keys to get the length of a request and do not assume the
            seconds match the shift on historical rows: read `working_days` and
            `workshift_seconds_per_day`, which normalize both shapes.
          additionalProperties:
            type: integer
            format: int32
            description: 'Requested duration for that day, in seconds.'
          example:
            '2024-03-01': 28800
            '2024-03-04': 28800
            '2024-03-05': 14400
        working_days:
          type: number
          description: |
            How long the request is, in working days the employee actually consumes:
            weekends, public holidays, company special holidays and days already taken by
            another absence are excluded, and each remaining day is measured against that
            employee's own scheduled day. A part-timer's 4h day therefore counts as `1`,
            while 4h out of an 8h day counts as `0.5`.

            This is the same figure the approval debits from the employee's balance, so it
            never disagrees with the amount charged. Prefer it over deriving a length from
            `start`/`end`: that difference is exclusive (Aug 3 → Aug 7 is 5 days, not 4) and
            counts days nobody works.

            Whole counts serialize without a fractional part (`5`, not `5.0`); half days
            appear as `.5`.
          example: 4.5
        total_seconds:
          type: integer
          format: int32
          description: |
            Sum of the booked seconds in `requested_time`, i.e. the same period expressed as
            time rather than days. `0` when the request has no per-day breakdown.
          example: 129600
        workshift_seconds_per_day:
          type: integer
          format: int32
          description: |
            What one full working day is worth for this employee, in seconds. It is the yardstick
            every booked day is measured against. `28800` on a standard 8h shift, `14400` for
            somebody contracted to 4h days. Use it to render a booking as a fraction of a day
            without assuming 8h.
          example: 28800
        is_half_day:
          type: boolean
          description: |
            True when either end of the request is a half day. The single flag a list badge
            needs; `starts_half_day` / `ends_half_day` say which end.
          example: true
        starts_half_day:
          type: boolean
          description: |
            True when the first day is a half day: the employee works that morning and
            leaves. `start_time` then carries the hour they leave.
          example: true
        ends_half_day:
          type: boolean
          description: |
            True when the last day is a half day: the absence covers that morning and the
            employee is back after it. `end_time` then carries the hour they return.

            On a single-day half day both this and `starts_half_day` are true, and both hours
            are filled in.
          example: false
        start_time:
          type:
            - string
            - 'null'
          description: |
            Local wall-clock hour (`HH:MM`) the absence begins on a half-day start. Null when
            the request does not start on a half day. Taken from the request's own stored
            time when it has one, otherwise the tenant's configured AM/PM split
            (`TEMPUS_HALF_DAY_SPLIT`, default `12:00`).
          example: '14:00'
        end_time:
          type:
            - string
            - 'null'
          description: |
            Local wall-clock hour (`HH:MM`) the absence ends on a half-day end. Null when the
            request does not end on a half day. Same source as `start_time`.
          example: '18:00'
        working_day_details:
          type: array
          description: |
            Per-day breakdown of the request, working days only, in date order. The same
            days as `requested_time` with the half-day verdict and hours resolved per day.

            Hours only ever land on the two ends: a day in the middle of a range has no clock
            time of its own, and a single-day request is both ends at once.
          items:
            type: object
            required:
              - date
              - seconds
              - is_half_day
              - start_time
              - end_time
            properties:
              date:
                type: string
                format: date
                description: 'The day, as `YYYY-MM-DD`.'
                example: '2026-08-03'
              seconds:
                type: integer
                format: int32
                description: |
                  Seconds booked off on this day, scaled to the employee's own scheduled day.
                example: 14400
              is_half_day:
                type: boolean
                description: |
                  True when this day's booked seconds fall short of a full day for this
                  employee (see `workshift_seconds_per_day`), allowing 15 minutes of
                  tolerance for lunch and rounding.
                example: true
              start_time:
                type:
                  - string
                  - 'null'
                description: |
                  Hour (`HH:MM`) the absence starts on this day. Non-null only on a half-day
                  first day (or a single-day half day).
                example: '12:00'
              end_time:
                type:
                  - string
                  - 'null'
                description: |
                  Hour (`HH:MM`) the absence ends on this day. Non-null only on a half-day
                  last day (or a single-day half day).
                example: null
        comment:
          type:
            - string
            - 'null'
          description: |
            Free-form note attached to the absence request (mirrors the transaction's
            `note`). Null when no comment was provided.
          example: 'Family event, returning Wednesday afternoon.'
        accepted_by:
          type: array
          description: |
            Every validator that must sign off on this request, with their individual
            decision. One entry per approval record; empty when the request has no
            assigned validators yet. A request is fully accepted only once every entry
            reports `accepted`.
          items:
            type: object
            required:
              - employee_id
              - status
            properties:
              employee_id:
                type:
                  - string
                  - 'null'
                format: uuid
                description: |
                  Identifier of the Tempus employee acting as validator for this
                  approval.
                example: 550e8400-e29b-41d4-a716-446655440004
              status:
                type: string
                enum:
                  - pending
                  - accepted
                  - rejected
                description: |
                  This validator's decision. `pending` awaits their action; `accepted`
                  and `rejected` record the outcome.
                example: pending
        next_availability:
          type: object
          description: |
            When an employee is next at work **if the request carrying this object goes through**,
            next to what the general next-availability answer says today. The validator's view of a
            request: no second call, and no cache between the queue and the date.

            It is deliberately not the same question as `GET /user/{employee_id}/next-availability`:

            - **Anchored at the request, not at today**, so it reports the day *this* booking frees
              rather than the next free day counting from now.
            - **Counts what has been decided plus this one request.** The base is what has been
              signed off (accepted, plus an accepted absence somebody has asked to cancel — still
              time off until that cancellation is approved). Other queued requests are left out:
              they may be refused, and a date that moves because of a request this validator has not
              seen is not one they can act on. (`current` does count every pending row — that
              difference is intentional.)
            - **A removal reads as a reduction**, so its answer moves *earlier*, often into the past
              (`in_past`), which is the signal that the employee is already back.

            Absence, illness, special leave and legal holiday only. Home office never carries it: a
            home office day is governed by a weekly limit, not time off that moves an availability
            date. Neither does a request that can no longer move a date — `rejected`, `canceled` and
            `removed`.

            **Where it appears:** the absence lists (`/absences`, `/user/{employee_id}/absences`), the
            absence-request reads and writes (`/absence-requests`, `/user/{employee_id}/absence-requests`
            and its `POST`/`PUT`), `POST /user/{employee_id}/absence-removal-requests`, and both
            validator queues (`/validator/pending-requests` — on each `absence_requests[]` /
            `absence_removals[]` entry — and v2 `pending-requests/absences`). It is **not** on the
            cancel responses (`POST .../absence-requests/{id}/cancel`), which report the outcome of an
            employee's own action rather than something a validator is weighing up.

            On the resource-backed payloads the key is **omitted** when there is nothing to say; on
            the v1 validator queue, whose entries are built by hand, it is always present and `null`
            in that case. Both mean the same thing.
          required:
            - if_approved
            - current
          properties:
            if_approved:
              type: object
              description: 'Availability as it would stand with this request applied.'
              required:
                - absent_from
                - next_available_date
                - next_available_at
                - available_now
                - in_past
                - extends_current_absence
                - message
              properties:
                absent_from:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: |
                    First day, today or later, that this request itself takes off. Null when it takes
                    nothing off in the future: a removal request, or days that have all been and gone.
                  example: '2026-08-13'
                next_available_date:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: |
                    The day the employee is back at work under this scenario. Null only when no
                    working day was found within the search horizon — an employee with no work shift,
                    or one whose contract has ended.
                  example: '2026-08-17'
                next_available_at:
                  type:
                    - string
                    - 'null'
                  description: |
                    Exact moment they are back (`YYYY-MM-DD HH:MM:SS`) when a half day pins one down;
                    null when only the date is meaningful.
                  example: null
                available_now:
                  type: boolean
                  description: |
                    Whether the employee is at work right now under this scenario. True together with
                    a future `absent_from` is the ordinary case for a request that starts later.
                  example: true
                in_past:
                  type: boolean
                  description: |
                    True when `next_available_date` is already behind us, i.e. approving this would
                    not keep anybody away from now on. Render it as "already available" rather than as
                    a return date.
                  example: false
                extends_current_absence:
                  type: boolean
                  description: |
                    True when this request starts on the very day the employee would otherwise have
                    come back, so it lengthens the absence already in place rather than opening a
                    separate one. False for a request with working days in between — show
                    `absent_from` as well as the return date in that case, or the return date reads as
                    a contradiction of `available_now`.
                  example: false
                message:
                  type:
                    - string
                    - 'null'
                  description: |
                    Ready-to-display line, already covering the three cases: `Available on
                    2026-08-17`, `Off from 2026-08-13, available on 2026-08-17`, or `Already available
                    (was back on 2026-08-03)`. Show it as returned.
                  example: 'Off from 2026-08-13, available on 2026-08-17'
            current:
              type: object
              description: |
                Today's general answer, unchanged — the same figure
                `GET /user/{employee_id}/next-availability` returns, so the two screens never disagree.
              required:
                - next_available_date
                - message
              properties:
                next_available_date:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: |
                    Next day the employee is available, counting from now. Null when they are
                    available right now.
                  example: '2026-08-12'
                message:
                  type:
                    - string
                    - 'null'
                  description: 'Ready-to-display line, or null while the employee is available.'
                  example: 'Back on 2026-08-12'
          example:
            if_approved:
              absent_from: '2026-08-13'
              next_available_date: '2026-08-17'
              next_available_at: null
              available_now: true
              in_past: false
              extends_current_absence: false
              message: 'Off from 2026-08-13, available on 2026-08-17'
            current:
              next_available_date: '2026-08-12'
              message: 'Back on 2026-08-12'
        created:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Timestamp when the absence request was created, as an ISO 8601 string. Null
            when not set.
          example: '2024-02-15T10:00:00+00:00'
          readOnly: true
        modified:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Timestamp when the absence request was last updated, as an ISO 8601 string.
            Null when not set.
          example: '2024-02-16T09:30:00+00:00'
          readOnly: true
      example:
        id: 550e8400-e29b-41d4-a716-446655440000
        mxvp_user_id: 550e8400-e29b-41d4-a716-446655440001
        employee_id: 550e8400-e29b-41d4-a716-446655440002
        requester_id: 550e8400-e29b-41d4-a716-446655440002
        creator_id: 550e8400-e29b-41d4-a716-446655440002
        ext_id: 550e8400-e29b-41d4-a716-446655440009
        company_id: 550e8400-e29b-41d4-a716-446655440003
        absence_request_id: 550e8400-e29b-41d4-a716-446655440000
        holiday_id: null
        status: accepted
        type: legal
        sub_type: null
        start: '2026-08-03T00:00:00+00:00'
        end: '2026-08-05T00:00:00+00:00'
        requested_time:
          '2026-08-03': 14400
          '2026-08-04': 28800
          '2026-08-05': 28800
        working_days: 2.5
        total_seconds: 72000
        workshift_seconds_per_day: 28800
        is_half_day: true
        starts_half_day: true
        ends_half_day: false
        start_time: '12:00'
        end_time: null
        working_day_details:
          -
            date: '2026-08-03'
            seconds: 14400
            is_half_day: true
            start_time: '12:00'
            end_time: null
          -
            date: '2026-08-04'
            seconds: 28800
            is_half_day: false
            start_time: null
            end_time: null
          -
            date: '2026-08-05'
            seconds: 28800
            is_half_day: false
            start_time: null
            end_time: null
        comment: 'Family event, returning Thursday.'
        accepted_by:
          -
            employee_id: 550e8400-e29b-41d4-a716-446655440004
            status: accepted
        next_availability:
          if_approved:
            absent_from: '2026-08-03'
            next_available_date: '2026-08-06'
            next_available_at: null
            available_now: true
            in_past: false
            extends_current_absence: false
            message: 'Off from 2026-08-03, available on 2026-08-06'
          current:
            next_available_date: null
            message: null
        created: '2026-07-28T10:00:00+00:00'
        modified: '2026-07-29T09:30:00+00:00'
    TempusTransactionApproval:
      type: object
      description: |
        Approval (validation) record for a Tempus absence request, as serialized by the
        V1 `TempusTransactionApprovalResource`. Each record represents one validator's
        decision on a single absence request (`tempus_transaction_id`): whether it is
        still pending, accepted, or rejected, together with an optional comment.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Several keys are renamed projections of model attributes:
        `mxvp_user_id` is the tenant identifier (`pbx_id`), `absence_request_id` is the
        related transaction id (`tempus_transaction_id`), and `comment` is the stored
        `note`. The `ext_id` field is a computed extension identifier resolved from the
        validator. The `validator` object is only present when the `validator` relation
        is loaded on the model; when absent the key is omitted entirely. The
        `holiday_id` key is always returned but currently always null (reserved for
        future use).
      required:
        - id
        - mxvp_user_id
        - absence_request_id
        - ext_id
        - status
        - comment
        - create_time
        - modified
        - holiday_id
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the approval record.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this approval record (the model's
            `pbx_id`). May be null for records not bound to a specific tenant.
          example: 550e8400-e29b-41d4-a716-446655440001
        absence_request_id:
          type: string
          format: uuid
          description: |
            Identifier of the absence request this approval belongs to (the related
            Tempus transaction id).
          example: 550e8400-e29b-41d4-a716-446655440002
        ext_id:
          type:
            - string
            - 'null'
          description: |
            Extension identifier of the validating employee, computed from the
            validator. Null when the validator has no associated extension.
          example: '201'
        validator:
          type: object
          description: |
            Summary of the employee who is responsible for this validation. Only
            present when the `validator` relation is loaded on the model; otherwise the
            key is omitted from the response.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the validating employee.'
              example: 550e8400-e29b-41d4-a716-446655440003
            name:
              type:
                - string
                - 'null'
              description: |
                Display name of the validating employee, falling back to the linked
                user's name when the employee has no name of its own. May be null.
              example: 'Jane Smith'
        status:
          type: string
          enum:
            - pending
            - accepted
            - rejected
          description: |
            Current decision on the absence request: `pending` while awaiting the
            validator, `accepted` when approved, or `rejected` when declined.
          example: pending
        comment:
          type:
            - string
            - 'null'
          description: |
            Optional free-form note left by the validator explaining the decision (the
            model's `note`). Null when no comment was provided.
          example: 'Approved, please coordinate handover with the team.'
        create_time:
          type:
            - string
            - 'null'
          format: date-time
          description: 'ISO 8601 timestamp of when the approval record was created.'
          example: '2024-03-01T08:29:07+00:00'
          readOnly: true
        modified:
          type:
            - string
            - 'null'
          format: date-time
          description: 'ISO 8601 timestamp of when the approval record was last updated.'
          example: '2024-03-01T09:15:42+00:00'
          readOnly: true
        holiday_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Reserved for a future link to a holiday record. Always returned but
            currently always null.
          example: null
    TempusCorrection:
      type: object
      description: |
        A Tempus time-point correction request as serialized by the V1
        `CorrectionResource`. A correction captures a requested change to an
        employee's recorded time point (its time, status, or sub-status), the values
        before and after the change, the approval workflow state, and a count of how
        many validators have accepted or refused it.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Two timestamp columns are renamed in the payload:
        `created_at` is exposed as `create_time` and `updated_at` as `update_time`.
        The `mxvp_user_id` key carries the owning Pbx (tenant) identifier (the
        model's `pbx_id`). The `requester_ext_id` key is the requesting employee's
        identifier.

        The nested `timepoint` object is only present when the related time point is
        loaded on the model; when present, its `status` and `substatuses` members are
        themselves only included when those relations are loaded.
      required:
        - id
        - mxvp_user_id
        - timepoint_id
        - requester_ext_id
        - new_status_id
        - new_sub_status_id
        - old_status_id
        - old_sub_status_id
        - new_time
        - old_time
        - correction_comment
        - new_comment
        - status
        - create_time
        - update_time
        - accepted_validations_count
        - refused_validations_count
        - accepted_by
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the correction request.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: "Identifier of the Pbx (tenant) that owns this correction (the model's pbx_id)."
          example: 550e8400-e29b-41d4-a716-446655440001
        timepoint_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the time point this correction targets. Null when the
            correction requests the creation of a brand new time point rather than a
            change to an existing one.
          example: 550e8400-e29b-41d4-a716-446655440002
        requester_ext_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the employee who requested the correction. Resolved from the
            related requester employee when loaded, falling back to the stored
            employee_id. Null when no requesting employee can be determined.
          example: 550e8400-e29b-41d4-a716-446655440003
        new_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus status the time point should be changed to. Null
            when the correction does not change the status.
          example: 550e8400-e29b-41d4-a716-446655440004
        new_sub_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus sub-status the time point should be changed to.
            Null when the correction does not change the sub-status.
          example: 550e8400-e29b-41d4-a716-446655440005
        old_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus status the time point had before the correction.
            Null when no prior status applies.
          example: 550e8400-e29b-41d4-a716-446655440006
        old_sub_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus sub-status the time point had before the
            correction. Null when no prior sub-status applies.
          example: 550e8400-e29b-41d4-a716-446655440007
        new_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Location the correction asks the time point to be recorded at. Null when
            the correction does not touch the location, which is NOT the same as asking
            for the location to be cleared: acceptance leaves the time point's current
            location exactly as it is. Always null on corrections raised before this
            field existed.
          example: 550e8400-e29b-41d4-a716-446655440010
        old_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            The location the time point was pointed at when the correction was raised.
            A snapshot, so the requested move reads as old -> new and so the reversal
            created by cancelling an accepted correction can swap the pair. Null when
            the time point had no location, or when the correction adds a new one.
          example: 550e8400-e29b-41d4-a716-446655440011
        old_location:
          type:
            - object
            - 'null'
          description: |
            The location the time point was pointed at when the correction was raised,
            resolved. Null when it had none.
          properties:
            id:
              type: string
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440011
            name:
              type: string
              example: 'HQ Luxembourg'
            latitude:
              type:
                - number
                - 'null'
              format: double
              example: 49.6008
            longitude:
              type:
                - number
                - 'null'
              format: double
              example: 6.133
            geofence_radius_m:
              type:
                - integer
                - 'null'
              example: 150
        new_location:
          type:
            - object
            - 'null'
          description: |
            The location the correction asks for, resolved. Null when the correction
            does not touch the location.
          properties:
            id:
              type: string
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440010
            name:
              type: string
              example: 'Remote office'
            latitude:
              type:
                - number
                - 'null'
              format: double
              example: 49.612
            longitude:
              type:
                - number
                - 'null'
              format: double
              example: 6.13
            geofence_radius_m:
              type:
                - integer
                - 'null'
              example: 200
        new_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Requested new timestamp for the time point, in ISO 8601 format. A null
            value on a correction targeting an existing time point indicates a removal
            (deletion) request.
          example: '2024-03-01T09:00:00.000000Z'
        old_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Original timestamp of the time point before the correction, in ISO 8601
            format. Null when no prior time applies.
          example: '2024-03-01T08:30:00.000000Z'
        correction_comment:
          type:
            - string
            - 'null'
          description: |
            Free-form justification supplied by the requester explaining why the
            correction is needed. Null when no comment was given.
          example: 'Forgot to clock out at the end of the shift.'
        new_comment:
          type:
            - string
            - 'null'
          description: |
            Comment to be applied to the time point when the correction is accepted
            (used in particular when creating a new time point). Null when not set.
          example: 'Manual entry approved by supervisor.'
        status:
          type:
            - string
            - 'null'
          enum:
            - pending
            - accepted
            - rejected
            - canceled
            - rejected_closed
          description: |
            Workflow state of the correction request. `pending` awaits validator
            review, `accepted` has been approved and applied to the time point,
            `rejected` was refused, `canceled` was withdrawn, and `rejected_closed`
            was refused and closed. Legacy stored values `refused` and `refused_closed`
            are normalized to `rejected` and `rejected_closed` respectively.
          example: pending
        create_time:
          type: string
          format: date-time
          description: "Timestamp when the correction request was created, in ISO 8601 format (the model's created_at)."
          example: '2024-03-01T08:29:07.000000Z'
          readOnly: true
        update_time:
          type: string
          format: date-time
          description: "Timestamp when the correction request was last updated, in ISO 8601 format (the model's updated_at)."
          example: '2024-03-01T08:29:07.000000Z'
          readOnly: true
        accepted_validations_count:
          type: integer
          format: int32
          description: 'Number of validators who have accepted this correction request.'
          example: 1
        refused_validations_count:
          type: integer
          format: int32
          description: 'Number of validators who have refused this correction request.'
          example: 0
        accepted_by:
          type: array
          description: |
            Every validator that must sign off on this correction, with their
            individual decision. A correction may require multiple validators. One
            entry per approval record; empty when no validators are assigned yet.
          items:
            type: object
            required:
              - employee_id
              - status
            properties:
              employee_id:
                type:
                  - string
                  - 'null'
                format: uuid
                description: 'Identifier of the Tempus employee acting as validator.'
                example: 550e8400-e29b-41d4-a716-446655440004
              status:
                type: string
                enum:
                  - pending
                  - accepted
                  - rejected
                description: |
                  This validator's decision. `pending` awaits their action; `accepted`
                  and `rejected` record the outcome.
                example: pending
        timepoint:
          type: object
          description: |
            The time point this correction targets. Only present when the related
            time point is loaded on the model; absent otherwise.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the time point.'
              example: 550e8400-e29b-41d4-a716-446655440002
              readOnly: true
            mxvp_user_id:
              type: string
              format: uuid
              description: 'Identifier of the Pbx (tenant) that owns the time point.'
              example: 550e8400-e29b-41d4-a716-446655440001
            ext_id:
              type:
                - string
                - 'null'
              format: uuid
              description: |
                Identifier of the employee the time point belongs to. Resolved from the
                related employee when loaded, falling back to the time point's user
                identifier. Null when neither is available.
              example: 550e8400-e29b-41d4-a716-446655440003
            status_id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'Identifier of the Tempus status currently assigned to the time point.'
              example: 550e8400-e29b-41d4-a716-446655440004
            time:
              type:
                - string
                - 'null'
              format: date-time
              description: 'Start timestamp of the time point, in ISO 8601 format. Null when not set.'
              example: '2024-03-01T08:30:00.000000Z'
            migration_id:
              type:
                - string
                - 'null'
              description: |
                Legacy migration identifier carried in the time point metadata, used to
                trace records imported from a previous system. Null when not migrated.
              example: legacy-tp-10293
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                Soft-delete timestamp of the time point, in ISO 8601 format. Null when
                the time point has not been deleted.
              example: null
            status:
              type: object
              description: |
                The Tempus status assigned to the time point. Only present when the
                status relation is loaded; absent otherwise.
              properties:
                id:
                  type: string
                  format: uuid
                  description: 'Unique identifier of the status.'
                  example: 550e8400-e29b-41d4-a716-446655440004
                  readOnly: true
                mxvp_user_id:
                  type: string
                  format: uuid
                  description: 'Identifier of the Pbx (tenant) that owns the status.'
                  example: 550e8400-e29b-41d4-a716-446655440001
                name:
                  type:
                    - string
                    - 'null'
                  description: 'Display name of the status.'
                  example: Working
                icon:
                  type:
                    - string
                    - 'null'
                  description: 'CSS icon class used to represent the status, from its style metadata. Null when not set.'
                  example: 'la la-briefcase'
                fontcolor:
                  type:
                    - string
                    - 'null'
                  description: 'Font color (CSS color value) for the status label, from its style metadata. Null when not set.'
                  example: '#ffffff'
                backgroundcolor:
                  type:
                    - string
                    - 'null'
                  description: 'Background color (CSS color value) for the status badge, from its style metadata. Null when not set.'
                  example: '#2e7d32'
                css:
                  type:
                    - string
                    - 'null'
                  description: 'Additional CSS class applied to the status badge, from its style metadata. Null when not set.'
                  example: status-working
                comment:
                  type: integer
                  format: int32
                  enum:
                    - 0
                    - 1
                  description: |
                    Whether a comment is required when assigning this status, normalized
                    from the status metadata to an integer flag (0 = not required,
                    1 = required).
                  example: 0
                payable:
                  type:
                    - boolean
                    - 'null'
                  description: 'Whether time recorded under this status is payable. Null when not configured.'
                  example: true
                action:
                  type:
                    - string
                    - 'null'
                  description: 'Optional action keyword associated with the status, from its metadata. Null when none.'
                  example: clock_in
                migration_id:
                  type:
                    - string
                    - 'null'
                  description: 'Legacy migration identifier for the status, from its metadata. Null when not migrated.'
                  example: legacy-status-7
                delete_date:
                  type:
                    - string
                    - 'null'
                  format: date-time
                  description: 'Soft-delete timestamp of the status, in ISO 8601 format. Null when not deleted.'
                  example: null
            substatuses:
              type: array
              description: |
                Sub-statuses attached to the time point. Only present when the
                sub-status relation is loaded; may be empty.
              items:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the sub-status.'
                    example: 550e8400-e29b-41d4-a716-446655440005
                    readOnly: true
                  mxvp_user_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns the sub-status.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type:
                      - string
                      - 'null'
                    description: 'Display name of the sub-status.'
                    example: 'Client meeting'
                  icon:
                    type:
                      - string
                      - 'null'
                    description: 'CSS icon class used to represent the sub-status, from its style metadata. Null when not set.'
                    example: 'la la-users'
                  fontcolor:
                    type:
                      - string
                      - 'null'
                    description: 'Font color (CSS color value) for the sub-status label, from its style metadata. Null when not set.'
                    example: '#000000'
                  backgroundcolor:
                    type:
                      - string
                      - 'null'
                    description: 'Background color (CSS color value) for the sub-status badge, from its style metadata. Null when not set.'
                    example: '#bbdefb'
                  css:
                    type:
                      - string
                      - 'null'
                    description: 'Additional CSS class applied to the sub-status badge, from its style metadata. Null when not set.'
                    example: substatus-meeting
                  comment:
                    type: integer
                    format: int32
                    enum:
                      - 0
                      - 1
                    description: |
                      Whether a comment is required when assigning this sub-status,
                      normalized from the sub-status metadata to an integer flag
                      (0 = not required, 1 = required).
                    example: 0
                  action:
                    type:
                      - string
                      - 'null'
                    description: 'Optional action keyword associated with the sub-status, from its metadata. Null when none.'
                    example: null
                  delete_date:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Soft-delete timestamp of the sub-status, in ISO 8601 format. Null when not deleted.'
                    example: null
    TempusCorrectionApproval:
      type: object
      description: |
        A single approval (validation) decision attached to a Tempus time-point
        correction request, as serialized by the V1 `CorrectionApprovalResource`.

        When an employee submits a correction to their recorded time points, one or
        more validators are asked to approve or reject it. Each `TempusCorrectionApproval`
        records the decision of one validator for one correction. The `status` field
        carries the current decision state (pending until the validator acts).

        This object documents the exact keys returned by the resource, not the raw
        database columns. Several keys are renamed from their underlying columns:
        `mxvp_user_id` maps to the tenant (`pbx_id`), `ext_id` maps to the validating
        employee (`validator_id`), and `comment` maps to the stored `note`. The
        `validator` object is only present when the validator relation is eager-loaded
        on the model; it is absent (key omitted) otherwise.
      required:
        - id
        - mxvp_user_id
        - correction_id
        - ext_id
        - status
        - comment
        - create_time
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of this approval record.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this approval. Sourced from the
            model `pbx_id` column.
          example: 550e8400-e29b-41d4-a716-446655440001
        correction_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus time-point correction request this approval
            decision belongs to.
          example: 550e8400-e29b-41d4-a716-446655440002
        ext_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus employee acting as the validator for this
            correction. Sourced from the model `validator_id` column.
          example: 550e8400-e29b-41d4-a716-446655440003
        validator:
          type: object
          description: |
            Summary of the validating employee. Only present when the `validator`
            relation is eager-loaded on the model; the key is omitted when the relation
            is not loaded. The `name` falls back to the linked user's name when the
            employee record has no own name.
          properties:
            id:
              type: string
              format: uuid
              description: 'Identifier of the validating employee.'
              example: 550e8400-e29b-41d4-a716-446655440003
            name:
              type:
                - string
                - 'null'
              description: 'Display name of the validating employee.'
              example: 'Jane Smith'
        status:
          type: string
          enum:
            - pending
            - accepted
            - rejected
          description: |
            Current decision state of this approval. `pending` means the validator has
            not yet acted, `accepted` means the correction was approved, and `rejected`
            means it was declined.
          example: pending
        comment:
          type:
            - string
            - 'null'
          description: |
            Free-form note left by the validator explaining the decision. Sourced from
            the model `note` column. Null when no note was provided.
          example: 'Approved after confirming the corrected clock-in time with the team lead.'
        create_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            ISO 8601 timestamp of when this approval record was created. Null if the
            creation timestamp is unavailable.
          example: '2024-03-01T08:29:07+00:00'
          readOnly: true
    TempusCorrectionList:
      type: object
      description: |
        A Tempus time point correction as serialized by the V1 `CorrectionListResource`.
        A correction is a request to change, add, or remove an employee's recorded
        attendance time point (for example fixing a missed clock-in, adjusting a start
        time, or changing the recorded status). Each correction belongs to exactly one
        Pbx (tenant), references the employee who requested it, and once accepted is
        applied to the underlying time point.

        A correction captures both the original ("old") and the requested ("new")
        values for the affected time point: its timestamp, status, and sub-status. When
        `timepoint_id` is null the correction requests creating a brand-new time point;
        when `new_time` is null the correction requests removing the referenced time
        point.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The status workflow fields `accepted_by`,
        `accepted_validations_count`, and `refused_validations_count`, and the
        `deleted_at` soft-delete timestamp, exist on the model but are not exposed by
        this resource.

        The `requesterExt`, `newStatus`, and `oldStatus` properties are optional
        expansions: they are present only when explicitly requested through the
        `include` query parameter (for example `?include=requesterExt,newStatus,oldStatus`)
        and the corresponding relation could be resolved. When omitted from the
        `include` list they are absent from the response entirely.
      required:
        - id
        - mxvp_user_id
        - timepoint_id
        - requester_ext_id
        - new_status_id
        - new_sub_status_id
        - old_status_id
        - old_sub_status_id
        - new_time
        - old_time
        - correction_comment
        - new_comment
        - status
        - create_time
        - update_time
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique correction identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this correction. Exposed under the
            legacy field name `mxvp_user_id`; it maps to the model's `pbx_id` column.
          example: 550e8400-e29b-41d4-a716-446655440001
        timepoint_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the existing time point this correction targets. Null when the
            correction requests creating a new time point rather than amending an
            existing one.
          example: 550e8400-e29b-41d4-a716-446655440002
        requester_ext_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus employee who requested the correction (the model's
            `employee_id`). When the `requester` relation is loaded its id is used;
            otherwise the stored `employee_id` is returned. Null when no requesting
            employee is recorded.
          example: 550e8400-e29b-41d4-a716-446655440003
        new_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus status requested for the corrected time point.
            References a `TempusStatus` record. Null when the correction does not change
            the status.
          example: 550e8400-e29b-41d4-a716-446655440004
        new_sub_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus sub-status requested for the corrected time point.
            References a `TempusSubStatus` record. Null when no sub-status change is
            requested.
          example: 550e8400-e29b-41d4-a716-446655440005
        old_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus status that was recorded on the time point before
            the correction. References a `TempusStatus` record. Null when no prior
            status applies.
          example: 550e8400-e29b-41d4-a716-446655440006
        old_sub_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus sub-status that was recorded on the time point
            before the correction. References a `TempusSubStatus` record. Null when no
            prior sub-status applies.
          example: 550e8400-e29b-41d4-a716-446655440007
        new_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Location the correction asks the time point to be recorded at. Null when the
            correction does not touch the location, which is NOT the same as asking for
            the location to be cleared: acceptance leaves the current one as it is.
            Always null on corrections raised before this field existed.
          example: 550e8400-e29b-41d4-a716-446655440010
        old_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            The location the time point was pointed at when the correction was raised.
            A snapshot, so the requested move reads as old -> new.
          example: 550e8400-e29b-41d4-a716-446655440011
        new_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Requested timestamp for the corrected time point, in ISO 8601 form. Null
            when the correction requests removing the referenced time point rather than
            changing its time.
          example: '2024-03-01T08:29:07Z'
        old_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Original timestamp of the time point before the correction, in ISO 8601
            form. Null when there was no prior recorded time (for example an add
            request).
          example: '2024-03-01T08:00:00Z'
        correction_comment:
          type:
            - string
            - 'null'
          description: |
            Free-form justification entered by the requester explaining why the
            correction is needed. Null when no comment was provided.
          example: 'Forgot to clock in after lunch break.'
        new_comment:
          type:
            - string
            - 'null'
          description: |
            Comment to apply to the corrected (or newly created) time point. Null when
            no comment is supplied.
          example: 'Corrected start time per manager approval.'
        status:
          type:
            - string
            - 'null'
          enum:
            - pending
            - accepted
            - rejected
            - canceled
            - rejected_closed
          description: |
            Lifecycle state of the correction request. `pending` awaits validator
            approval; `accepted` has been applied to the time point; `rejected` was
            declined; `canceled` was withdrawn; `rejected_closed` was declined and the
            request is closed. Legacy stored values `refused` and `refused_closed` are
            normalised to `rejected` and `rejected_closed` respectively. Null when no
            status is set.
          example: pending
        create_time:
          type: string
          format: date-time
          description: 'Timestamp when the correction was created, in ISO 8601 form.'
          example: '2024-03-01T08:29:07Z'
          readOnly: true
        update_time:
          type: string
          format: date-time
          description: 'Timestamp when the correction was last updated, in ISO 8601 form.'
          example: '2024-03-01T09:15:42Z'
          readOnly: true
        requesterExt:
          type:
            - object
            - 'null'
          description: |
            Summary of the requesting employee's extension. Optional expansion: present
            only when `requesterExt` is passed in the `include` query parameter and the
            `requester` relation resolves. Null when requested but the requester cannot
            be resolved.
          properties:
            id:
              type: string
              format: uuid
              description: 'Identifier of the requesting Tempus employee.'
              example: 550e8400-e29b-41d4-a716-446655440003
            number:
              type:
                - string
                - 'null'
              description: |
                Primary extension number of the requester's linked user. Null when the
                user has no extension assigned.
              example: '1042'
            name:
              type:
                - string
                - 'null'
              description: 'First name of the requesting employee.'
              example: Jane
            name2:
              type:
                - string
                - 'null'
              description: 'Last name of the requesting employee.'
              example: Smith
        newStatus:
          type:
            - object
            - 'null'
          description: |
            Full details of the requested ("new") Tempus status. Optional expansion:
            present only when `newStatus` is passed in the `include` query parameter and
            the `newStatus` relation resolves. Null when requested but unresolved.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the status.'
              example: 550e8400-e29b-41d4-a716-446655440004
            mxvp_user_id:
              type: string
              format: uuid
              description: |
                Identifier of the Pbx (tenant) that owns the status (maps to the model's
                `pbx_id`).
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type: string
              description: 'Display name of the status.'
              example: Working
            icon:
              type:
                - string
                - 'null'
              description: |
                CSS icon class used to represent the status in the UI. Null when no icon
                is configured.
              example: 'la la-briefcase'
            fontcolor:
              type:
                - string
                - 'null'
              description: 'Foreground (font) colour for the status badge. Null when unset.'
              example: '#ffffff'
            backgroundcolor:
              type:
                - string
                - 'null'
              description: 'Background colour for the status badge. Null when unset.'
              example: '#2e7d32'
            css:
              type:
                - string
                - 'null'
              description: 'Additional CSS class applied to the status badge. Null when unset.'
              example: status-working
            comment:
              type: boolean
              description: |
                Whether a comment is required when applying this status. Defaults to
                false.
              example: false
            payable:
              type: boolean
              description: 'Whether time spent in this status counts as payable working time.'
              example: true
            action:
              type:
                - string
                - 'null'
              description: |
                Optional workflow action associated with the status (stored in the
                status meta data). Null when none is configured.
              example: clock_in
            migration_id:
              type:
                - string
                - 'null'
              description: |
                Identifier carried over from a legacy migration of this status. Null when
                the status was not migrated.
              example: '12345'
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                Soft-delete timestamp of the status, in ISO 8601 form. Null when the
                status is active (not deleted).
              example: null
        oldStatus:
          type:
            - object
            - 'null'
          description: |
            Full details of the previously recorded ("old") Tempus status, using the
            same shape as `newStatus`. Optional expansion: present only when `oldStatus`
            is passed in the `include` query parameter and the `oldStatus` relation
            resolves. Null when requested but unresolved.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the status.'
              example: 550e8400-e29b-41d4-a716-446655440006
            mxvp_user_id:
              type: string
              format: uuid
              description: |
                Identifier of the Pbx (tenant) that owns the status (maps to the model's
                `pbx_id`).
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type: string
              description: 'Display name of the status.'
              example: Break
            icon:
              type:
                - string
                - 'null'
              description: 'CSS icon class used to represent the status in the UI. Null when unset.'
              example: 'la la-coffee'
            fontcolor:
              type:
                - string
                - 'null'
              description: 'Foreground (font) colour for the status badge. Null when unset.'
              example: '#000000'
            backgroundcolor:
              type:
                - string
                - 'null'
              description: 'Background colour for the status badge. Null when unset.'
              example: '#fbc02d'
            css:
              type:
                - string
                - 'null'
              description: 'Additional CSS class applied to the status badge. Null when unset.'
              example: status-break
            comment:
              type: boolean
              description: 'Whether a comment is required when applying this status. Defaults to false.'
              example: false
            payable:
              type: boolean
              description: 'Whether time spent in this status counts as payable working time.'
              example: false
            action:
              type:
                - string
                - 'null'
              description: |
                Optional workflow action associated with the status (stored in the
                status meta data). Null when none is configured.
              example: null
            migration_id:
              type:
                - string
                - 'null'
              description: |
                Identifier carried over from a legacy migration of this status. Null when
                the status was not migrated.
              example: null
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                Soft-delete timestamp of the status, in ISO 8601 form. Null when the
                status is active (not deleted).
              example: null
    TempusPendingCorrection:
      type: object
      description: |
        A pending Tempus time-point correction request as serialized by the V1
        `PendingCorrectionResource`. These are change requests raised by an employee
        (or on their behalf) to add, modify, or remove a time-point (clock event) on
        their attendance sheet, awaiting validation by an authorized approver.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Several fields are derived: `requested_ext_id` and
        `full_name` are resolved from the related employee, `date` is the formatted
        creation date, and the date/time fields are reformatted from the model's
        `new_time` and `old_time` timestamps. The status objects (`old_status`,
        `new_status`, `old_sub_status`, `new_sub_status`) are populated only when the
        corresponding relationship is loaded on the model; when a relation is not
        loaded, or no status is set, the field is null.

        A correction may have no "old" side (for example when it requests adding a
        brand-new time-point): in that case `old_status`, `old_sub_status`,
        `old_datetime`, and `old_time` are all null.
      required:
        - id
        - requested_ext_id
        - full_name
        - date
        - timepoint_id
        - old_status
        - new_status
        - old_sub_status
        - new_sub_status
        - new_datetime
        - old_datetime
        - new_time
        - old_time
        - correction_comment
        - new_status_id
        - new_comment
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the correction request.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        requested_ext_id:
          type:
            - string
            - 'null'
          description: |
            Telephony extension number of the employee who is the subject of this
            correction, resolved from the linked employee record. Null when the
            employee has no associated extension.
          example: '1042'
        full_name:
          type: string
          description: |
            Display name of the employee the correction applies to, taken from the
            employee's full name when available, otherwise assembled from their first
            and last name. May be an empty string when no name is on file.
          example: 'Jane Smith'
        date:
          type:
            - string
            - 'null'
          description: |
            Human-readable creation date of the correction request, formatted as
            "Day YYYY-MM-DD" (the abbreviated weekday followed by the ISO date). Null
            when no creation timestamp is set.
          example: 'Mon 2024-03-04'
        timepoint_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the existing time-point this correction modifies or removes.
            Null when the correction requests adding a new time-point that does not
            yet exist.
          example: 550e8400-e29b-41d4-a716-446655440010
        old_status:
          type:
            - object
            - 'null'
          description: |
            The time-point's status before the correction, including its display
            styling. Null when there is no prior status (for example an add request)
            or when the `oldStatus` relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the status.'
              example: 550e8400-e29b-41d4-a716-446655440020
            name:
              type: string
              description: 'Display name of the status.'
              example: Working
            font_color:
              type: string
              description: |
                CSS font color used to render the status label. Empty string when no
                color is configured.
              example: '#ffffff'
            background_color:
              type: string
              description: |
                CSS background color used to render the status badge. Empty string
                when no color is configured.
              example: '#2e7d32'
            icon:
              type: string
              description: |
                CSS icon class used to render the status icon. Empty string when no
                icon is configured.
              example: 'la la-briefcase'
        new_status:
          type:
            - object
            - 'null'
          description: |
            The time-point's requested status after the correction, including its
            display styling. Null when no new status is requested or when the
            `newStatus` relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the status.'
              example: 550e8400-e29b-41d4-a716-446655440021
            name:
              type: string
              description: 'Display name of the status.'
              example: 'Home Office'
            font_color:
              type: string
              description: |
                CSS font color used to render the status label. Empty string when no
                color is configured.
              example: '#ffffff'
            background_color:
              type: string
              description: |
                CSS background color used to render the status badge. Empty string
                when no color is configured.
              example: '#1565c0'
            icon:
              type: string
              description: |
                CSS icon class used to render the status icon. Empty string when no
                icon is configured.
              example: 'la la-home'
        old_sub_status:
          type:
            - object
            - 'null'
          description: |
            The time-point's sub-status before the correction, including its display
            styling. Null when there is no prior sub-status or when the `oldSubStatus`
            relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the sub-status.'
              example: 550e8400-e29b-41d4-a716-446655440022
            name:
              type: string
              description: 'Display name of the sub-status.'
              example: Meeting
            font_color:
              type: string
              description: |
                CSS font color used to render the sub-status label. Empty string when
                no color is configured.
              example: '#000000'
            background_color:
              type: string
              description: |
                CSS background color used to render the sub-status badge. Empty string
                when no color is configured.
              example: '#fff59d'
            icon:
              type: string
              description: |
                CSS icon class used to render the sub-status icon. Empty string when
                no icon is configured.
              example: 'la la-users'
        new_sub_status:
          type:
            - object
            - 'null'
          description: |
            The time-point's requested sub-status after the correction, including its
            display styling. Null when no new sub-status is requested or when the
            `newSubStatus` relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the sub-status.'
              example: 550e8400-e29b-41d4-a716-446655440023
            name:
              type: string
              description: 'Display name of the sub-status.'
              example: Training
            font_color:
              type: string
              description: |
                CSS font color used to render the sub-status label. Empty string when
                no color is configured.
              example: '#000000'
            background_color:
              type: string
              description: |
                CSS background color used to render the sub-status badge. Empty string
                when no color is configured.
              example: '#b2dfdb'
            icon:
              type: string
              description: |
                CSS icon class used to render the sub-status icon. Empty string when
                no icon is configured.
              example: 'la la-graduation-cap'
        old_location:
          type:
            - object
            - 'null'
          description: |
            The location the time point was pointed at when the correction was raised.
            Null when it had none, or when the `oldLocation` relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440011
            name:
              type: string
              example: 'HQ Luxembourg'
            latitude:
              type:
                - number
                - 'null'
              format: double
              example: 49.6008
            longitude:
              type:
                - number
                - 'null'
              format: double
              example: 6.133
            geofence_radius_m:
              type:
                - integer
                - 'null'
              example: 150
        new_location:
          type:
            - object
            - 'null'
          description: |
            The location the correction asks the time point to be recorded at. Null
            when the correction does not touch the location, which is NOT the same as
            asking for it to be cleared: accepting leaves the current location as is.
          properties:
            id:
              type: string
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440010
            name:
              type: string
              example: 'Remote office'
            latitude:
              type:
                - number
                - 'null'
              format: double
              example: 49.612
            longitude:
              type:
                - number
                - 'null'
              format: double
              example: 6.13
            geofence_radius_m:
              type:
                - integer
                - 'null'
              example: 200
        new_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Raw identifier behind `new_location`. Null when the correction does not
            touch the location.
          example: 550e8400-e29b-41d4-a716-446655440010
        old_location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: 'Raw identifier behind `old_location`.'
          example: 550e8400-e29b-41d4-a716-446655440011
        new_datetime:
          type:
            - string
            - 'null'
          description: |
            Requested new time-point timestamp, formatted as "YYYY-MM-DD HH:MM:SS"
            (local PBX time). Null when no new time is requested (for example a
            removal request).
          example: '2024-03-04 09:00:00'
        old_datetime:
          type:
            - string
            - 'null'
          description: |
            Original time-point timestamp before the correction, formatted as
            "YYYY-MM-DD HH:MM:SS" (local PBX time). Null when there is no prior status
            (for example an add request) or when no original time is set.
          example: '2024-03-04 08:30:00'
        new_time:
          type:
            - string
            - 'null'
          description: |
            Requested new clock time only, formatted as "HH:MM" (local PBX time). Null
            when no new time is requested.
          example: '09:00'
        old_time:
          type:
            - string
            - 'null'
          description: |
            Original clock time only before the correction, formatted as "HH:MM"
            (local PBX time). Null when there is no prior status or no original time.
          example: '08:30'
        correction_comment:
          type:
            - string
            - 'null'
          description: |
            Free-form justification provided by the requester explaining why the
            correction is needed. Null when no comment was supplied.
          example: 'Forgot to clock in after lunch'
        new_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the requested new status. Null when the correction does not
            change the status. This is the raw foreign key; the resolved status object
            is exposed under `new_status`.
          example: 550e8400-e29b-41d4-a716-446655440021
        new_comment:
          type:
            - string
            - 'null'
          description: |
            Comment to be stored on the time-point itself once the correction is
            applied (distinct from `correction_comment`, which justifies the request).
            Null when no time-point comment is supplied.
          example: 'Client visit on site'
    TempusPendingCorrectionDetails:
      type: object
      description: |
        Compact summary of a single Tempus time point (clock event) that is awaiting
        manual correction by a validator, as serialized by the V1
        `PendingCorrectionDetailsResource`. It surfaces just enough context for a
        reviewer to identify the event in a pending-corrections list: when it occurred
        (split into a calendar date and a wall-clock time) and the presentation status
        it carries.

        The underlying `start_time` of the time point is a single timestamp; this
        resource deliberately splits it into separate `date` and `time` strings (both
        derived from the same moment) rather than returning a combined date-time value.

        The nested `status` object describes the Tempus status assigned to the time
        point along with the styling hints (colours and icon) the UI uses to render it.
        When the time point has no associated status, the status fields fall back to
        null identifiers and empty-string styling values.
      required:
        - id
        - date
        - time
        - status
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the time point awaiting correction.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        date:
          type:
            - string
            - 'null'
          format: date
          description: |
            Calendar date of the time point's start, formatted as `YYYY-MM-DD`.
            Null when the time point has no recorded start time.
          example: '2024-03-01'
        time:
          type:
            - string
            - 'null'
          description: |
            Wall-clock time of the time point's start, formatted as `HH:MM:SS`
            (24-hour). Null when the time point has no recorded start time.
          example: '08:29:07'
        status:
          type: object
          description: |
            The Tempus status assigned to this time point, together with the styling
            hints used to render it. Always present as an object; its `id` and `name`
            are null and the styling values are empty strings when no status is linked
            to the time point.
          required:
            - id
            - name
            - font_color
            - background_color
            - icon
          properties:
            id:
              type:
                - string
                - 'null'
              format: uuid
              description: |
                Unique identifier of the linked Tempus status, or null when the time
                point has no associated status.
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type:
                - string
                - 'null'
              description: |
                Human-readable name of the status (for example a work, break, or
                absence label). Null when no status is linked.
              example: Working
            font_color:
              type: string
              description: |
                Foreground (text) colour used to render the status, as a CSS colour
                value (typically a hex code). Empty string when no styling is defined.
              example: '#FFFFFF'
            background_color:
              type: string
              description: |
                Background colour used to render the status, as a CSS colour value
                (typically a hex code). Empty string when no styling is defined.
              example: '#2E7D32'
            icon:
              type: string
              description: |
                Icon CSS class used to represent the status in the UI. Empty string
                when no styling is defined.
              example: 'la la-briefcase'
    TempusTimePoint:
      type: object
      description: |
        A Tempus time point as serialized by the V1 `TimePointResource`. A time point
        records a single interval during which an employee was in a given presence or
        attendance status (for example working, on break, or off). Each time point
        belongs to exactly one Pbx (tenant) and one user, references the status that
        was active during the interval, and is bounded by a `start_time` and an
        optional `end_time`.

        An open time point (one with `end_time` set to null) represents the employee's
        current, ongoing status. When a new time point is opened for an employee, any
        previously open time point for that same employee is automatically closed by
        setting its `end_time`.

        This object documents the exact keys returned by the resource, not every raw
        database column. Columns such as `successive_count`, `comment`, `mapping_id`,
        `deleted_at`, `created_by`, and `updated_by` exist on the model but are not
        exposed by this resource. The `sources`, `triggers`, and `meta_data` fields
        are stored as JSON and returned as free-form objects.

        Location data comes in three distinct parts that must not be conflated:
        `location_id` plus the nested `location` object describe the *configured*
        location record the employee selected; `device_gps` records where the
        *device* said it was; `location_check` is the comparison of the two.
      required:
        - id
        - pbx_id
        - user_id
        - status_id
        - start_time
        - is_synced
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique time point identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        pbx_id:
          type: string
          format: uuid
          description: 'Identifier of the Pbx (tenant) that owns this time point.'
          example: 550e8400-e29b-41d4-a716-446655440001
        user_id:
          type: string
          format: uuid
          description: 'Identifier of the user (employee) this time point belongs to.'
          example: 550e8400-e29b-41d4-a716-446655440002
        status_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus status that was active during this interval (for
            example working, break, or off). References a `TempusStatus` record.
          example: 550e8400-e29b-41d4-a716-446655440003
        location_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the location the status was recorded against. Null when no
            location was selected.
          example: 550e8400-e29b-41d4-a716-446655440010
        location:
          type:
            - object
            - 'null'
          description: |
            The configured location record referenced by `location_id`, including its
            own coordinates and geofence radius. Null when `location_id` is null.
            These are the location's *configured* coordinates, not the device's: see
            `device_gps` for the latter.
          properties:
            id:
              type: string
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440010
            name:
              type: string
              example: 'HQ Luxembourg'
            description:
              type:
                - string
                - 'null'
              example: null
            street_no:
              type:
                - string
                - 'null'
              example: '12'
            street:
              type:
                - string
                - 'null'
              example: 'Rue de Bonnevoie'
            city:
              type:
                - string
                - 'null'
              example: Luxembourg
            postal:
              type:
                - string
                - 'null'
              example: '1260'
            country_id:
              type:
                - string
                - 'null'
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440011
            latitude:
              type:
                - number
                - 'null'
              format: double
              description: "The location's configured latitude, in degrees."
              example: 49.6008
            longitude:
              type:
                - number
                - 'null'
              format: double
              description: "The location's configured longitude, in degrees."
              example: 6.133
            geofence_radius_m:
              type:
                - integer
                - 'null'
              description: 'Geofence radius around the configured point, in metres.'
              example: 150
            is_fixed_location:
              type: boolean
              example: true
        start_time:
          type: string
          format: date-time
          description: 'Timestamp marking the beginning of the status interval.'
          example: '2024-03-01T08:29:07Z'
        end_time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Timestamp marking the end of the status interval. Null while the time
            point is still open, which indicates the employee's current ongoing
            status.
          example: '2024-03-01T12:00:00Z'
        sources:
          type:
            - object
            - 'null'
          description: |
            Free-form JSON object describing the origin systems that contributed to
            this time point (for example the cockpit UI, a badge reader, or an API
            client). Structure varies by integration. Null when no source data is
            recorded.
          additionalProperties: true
          example:
            channel: cockpit
            device_id: 550e8400-e29b-41d4-a716-446655440010
        triggers:
          type:
            - object
            - 'null'
          description: |
            Free-form JSON object describing the events that triggered the creation or
            closing of this time point (for example a manual status change or an
            automated rollover). Structure varies by integration. Null when no trigger
            data is recorded.
          additionalProperties: true
          example:
            type: manual_change
            actor_id: 550e8400-e29b-41d4-a716-446655440002
        meta_data:
          type:
            - object
            - 'null'
          description: |
            Free-form JSON object holding additional key-value metadata attached to
            the time point, exactly as the client sent it. Keys are
            integration-specific. Null when no metadata is stored.

            Two keys are written by the server rather than the client: `device_gps`
            and `location_check`, both also surfaced as top-level fields of this
            resource (see below).
          additionalProperties: true
          example:
            note: 'Started shift remotely'
            gpsLat: 49.95
            gpsLong: 6.133
        device_gps:
          type:
            - object
            - 'null'
          description: |
            The coordinates the client reported when this status was recorded, stored
            exactly as sent. Read from whichever field the client already uses
            (`gpsData`, or GPS keys inside `meta_data`, under any of the historical
            spellings such as `gpsLat` / `lat` / `latitude`).

            This is never derived from, corrected by, or overwritten with the
            coordinates configured on the selected location: it records where the
            device claimed to be, which is only useful as evidence if it is left
            untouched. Compare it with `location.latitude` / `location.longitude`,
            which describe the configured location record instead.

            Null when the request carried no usable fix (no coordinates at all, only
            one of the pair, or values outside the valid latitude / longitude range).
            A request with an unusable fix still succeeds, and whatever it sent is
            preserved verbatim under `meta_data`.
          required:
            - latitude
            - longitude
          properties:
            latitude:
              type: number
              format: double
              description: 'Latitude reported by the device, in degrees.'
              example: 49.95
            longitude:
              type: number
              format: double
              description: 'Longitude reported by the device, in degrees.'
              example: 6.133
            accuracy_m:
              type:
                - number
                - 'null'
              format: double
              description: |
                Accuracy radius of the fix in metres, as reported by the device. Null
                when the client sent none. Used as tolerance by `location_check`.
              example: 12.5
            captured_at:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                The device's GPS timestamp, parsed. Null when the client sent none or
                sent a value that could not be parsed.
              example: '2026-07-07T10:07:39+00:00'
            captured_at_raw:
              type:
                - string
                - number
                - 'null'
              description: |
                The GPS timestamp exactly as the client sent it: epoch milliseconds,
                epoch seconds, or an ISO 8601 string. Kept alongside the parsed value
                so nothing the client reported is lost.
              example: 1783418859289
          example:
            latitude: 49.95
            longitude: 6.133
            accuracy_m: 12.5
            captured_at: '2026-07-07T10:07:39+00:00'
            captured_at_raw: 1783418859289
        location_check:
          type:
            - object
            - 'null'
          description: |
            Comparison of `device_gps` against the selected location's configured
            coordinates and geofence radius. This is the integrity signal: it shows
            when an employee recorded a status against a location they were not
            actually at.

            Null when the time point has neither a device fix nor a location, and on
            time points written before this check existed.
          properties:
            location_id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'The location the status was recorded against, if any.'
              example: 550e8400-e29b-41d4-a716-446655440010
            location_latitude:
              type:
                - number
                - 'null'
              format: double
              description: "The location's configured latitude at the time of the check."
              example: 49.6008
            location_longitude:
              type:
                - number
                - 'null'
              format: double
              description: "The location's configured longitude at the time of the check."
              example: 6.133
            geofence_radius_m:
              type:
                - integer
                - 'null'
              description: "The location's configured geofence radius in metres."
              example: 150
            distance_m:
              type:
                - integer
                - 'null'
              description: |
                Distance in metres between the device fix and the location's
                configured point. Recorded whenever both sides have coordinates, even
                when the location has no geofence radius and no in-or-out verdict is
                possible: the distance alone is the useful signal.
              example: 38957
            within_geofence:
              type:
                - boolean
                - 'null'
              description: |
                Whether the device fix falls inside the geofence. The device's own
                reported accuracy is added to the radius as tolerance, so a poor fix
                slightly outside a small geofence is not treated as a discrepancy.
                Null when no verdict was possible.
              example: false
            verdict:
              type: string
              enum:
                - match
                - mismatch
                - unknown
              description: |
                `match`: the device fix is inside the geofence.
                `mismatch`: the device fix is outside it, meaning the selected
                location disagrees with where the device said it was.
                `unknown`: not enough data to judge, see `reason`.
              example: mismatch
            reason:
              type:
                - string
                - 'null'
              enum:
                - no_device_gps
                - no_location
                - location_without_coordinates
                - no_geofence_radius
                - null
              description: |
                Why the verdict is `unknown`. `no_device_gps`: the request carried no
                usable fix. `no_location`: no location was selected, or it does not
                belong to this tenant. `location_without_coordinates`: the location
                record has no coordinates configured. `no_geofence_radius`: the
                location has coordinates but no radius, so only `distance_m` is
                meaningful. Null when the verdict is `match` or `mismatch`.
              example: null
          example:
            location_id: 550e8400-e29b-41d4-a716-446655440010
            location_latitude: 49.6008
            location_longitude: 6.133
            geofence_radius_m: 150
            distance_m: 38957
            within_geofence: false
            verdict: mismatch
            reason: null
        is_synced:
          type: boolean
          description: |
            Whether this time point has been synchronized to the downstream
            time-and-attendance system. False until the record has been exported.
          example: false
        created_at:
          type:
            - string
            - 'null'
          format: date-time
          description: 'Timestamp when the time point was created.'
          example: '2024-03-01T08:29:07Z'
          readOnly: true
        updated_at:
          type:
            - string
            - 'null'
          format: date-time
          description: 'Timestamp when the time point was last updated.'
          example: '2024-03-01T08:29:07Z'
          readOnly: true
    TempusUserTimepointLegacy:
      type: object
      description: |
        A single Tempus time point (clock event) serialized in the legacy mobile-app
        format by the V1 `UserTimepointLegacyResource`. A time point records when an
        employee entered a given attendance status (for example "Working", "Break" or
        "Off"), optionally with a captured GPS location and a free-text comment.

        This object documents the exact keys returned by the resource, not the raw
        `tempus_time_points` columns. The `status` and `substatus` objects are
        flattened presentation views assembled from the related `TempusStatus` and
        `TempusSubStatus` records (their display style is read from each status's
        `style` JSON and its comment requirement from its `meta_data` JSON). The
        `gpsLong`, `gpsLat` and `gpsTimestamp` values are extracted from the time
        point's own `meta_data` JSON, tolerating several historical key spellings, and
        falling back to the normalised `device_gps` block for time points recorded
        since that block existed.

        The GPS fields (`gpsLong` / `gpsLat` / `gpsTimestamp` / `device_gps`) describe
        where the *device* said it was. The nested `location` object describes the
        *configured* location record the employee selected. `location_check` compares
        the two. The three are independent and must not be conflated.

        Several boolean-like flags (`status.comment`, `status.payable`,
        `substatus.comment`) are returned as the integers `1` or `0` rather than JSON
        booleans, preserving compatibility with the legacy client.
      required:
        - id
        - ext_id
        - time
        - status
        - comment
        - gpsLong
        - gpsLat
        - gpsTimestamp
        - substatus
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the time point (clock event).'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        ext_id:
          type:
            - string
            - 'null'
          description: |
            External employee identifier resolved from the `employee_id` route
            parameter, used by the legacy client to correlate the event with its own
            employee record. Null when no external mapping exists for the employee.
          example: EMP-10472
        time:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            ISO 8601 timestamp marking when this status began (the time point's
            `start_time`). Null only when no start time is recorded.
          example: '2024-03-01T08:29:07Z'
        status:
          type: object
          description: |
            The primary attendance status active from `time`, flattened from the
            related `TempusStatus` record together with its display style.
          required:
            - id
            - name
            - icon
            - fontcolor
            - backgroundcolor
            - css
            - comment
            - payable
          properties:
            id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'Identifier of the status. Null if the status is unavailable.'
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type:
                - string
                - 'null'
              description: 'Human-readable status name shown to the employee.'
              example: Working
            icon:
              type:
                - string
                - 'null'
              description: |
                CSS icon class used to render the status (from the status style's
                `icon_class`). Null when no icon is configured.
              example: 'la la-briefcase'
            fontcolor:
              type:
                - string
                - 'null'
              description: |
                Foreground (text) colour for the status label, as a CSS colour value
                (from the status style's `font_color`). Null when unset.
              example: '#ffffff'
            backgroundcolor:
              type:
                - string
                - 'null'
              description: |
                Background colour for the status label, as a CSS colour value (from
                the status style's `bg_color`). Null when unset.
              example: '#2e7d32'
            css:
              type: string
              description: |
                Additional CSS class string for the status (from the style's `css`,
                falling back to `css_class`). Empty string when none is configured.
              example: status-working
            comment:
              type: integer
              format: int32
              enum:
                - 0
                - 1
              description: |
                Whether a comment is required when selecting this status: 1 if
                required, 0 otherwise. Derived from the status `meta_data`
                (`comment_required` flag or a `comment` entry in its `flags` list).
              example: 0
            payable:
              type: integer
              format: int32
              enum:
                - 0
                - 1
              description: |
                Whether time spent in this status is payable working time: 1 if
                payable, 0 otherwise.
              example: 1
        comment:
          type:
            - string
            - 'null'
          description: |
            Free-text comment attached to this time point. Falls back to the
            `comment` key inside the time point's `meta_data` when no dedicated
            comment column value is present. Null when no comment was recorded.
          example: 'Started shift on site'
        gpsLong:
          type:
            - number
            - string
            - 'null'
          description: |
            Longitude of the captured GPS location, read from the time point's
            `meta_data` (accepting the `gpsLong`, `gps_long`, `longitude` or `lng`
            keys). The stored value may be a number or a string. Null when no
            location was captured.
          example: -73.9857
        gpsLat:
          type:
            - number
            - string
            - 'null'
          description: |
            Latitude of the captured GPS location, read from the time point's
            `meta_data` (accepting the `gpsLat`, `gps_lat`, `latitude` or `lat`
            keys). The stored value may be a number or a string. Null when no
            location was captured.
          example: 40.7484
        gpsTimestamp:
          type:
            - string
            - integer
            - 'null'
          description: |
            Timestamp at which the GPS location was captured, read from the time
            point's `meta_data` (accepting the `gpsTimestamp`, `gps_timestamp`,
            `timestamp` or `gps_time` keys). May be an ISO 8601 string or a Unix
            epoch value depending on the originating client. Null when no location
            was captured.
          example: '2024-03-01T08:29:05Z'
        device_gps:
          type:
            - object
            - 'null'
          description: |
            The coordinates the client reported, stored exactly as sent and never
            replaced by the coordinates configured on the selected location. This is
            the same fix the flat `gpsLat` / `gpsLong` / `gpsTimestamp` fields expose,
            in a normalised and typed form (a parsed timestamp, plus the reported
            accuracy, which the flat fields have no place for). Null when the time
            point carried no usable fix.
          properties:
            latitude:
              type: number
              format: double
              example: 49.95
            longitude:
              type: number
              format: double
              example: 6.133
            accuracy_m:
              type:
                - number
                - 'null'
              format: double
              description: 'Accuracy radius of the fix in metres, as reported by the device.'
              example: 12.5
            captured_at:
              type:
                - string
                - 'null'
              format: date-time
              description: "The device's GPS timestamp, parsed. Null when unparseable or absent."
              example: '2026-07-07T10:07:39+00:00'
            captured_at_raw:
              type:
                - string
                - number
                - 'null'
              description: 'The GPS timestamp exactly as the client sent it.'
              example: 1783418859289
        location_check:
          type:
            - object
            - 'null'
          description: |
            Comparison of `device_gps` against the selected location's configured
            coordinates and geofence radius: the signal that a status was recorded
            against a location the employee was not actually at. Same shape and
            semantics as on the `TempusTimePoint` model. Null when the time point has
            neither a device fix nor a location, and on time points written before
            this check existed.
          properties:
            location_id:
              type:
                - string
                - 'null'
              format: uuid
              example: 550e8400-e29b-41d4-a716-446655440010
            location_latitude:
              type:
                - number
                - 'null'
              format: double
              example: 49.6008
            location_longitude:
              type:
                - number
                - 'null'
              format: double
              example: 6.133
            geofence_radius_m:
              type:
                - integer
                - 'null'
              example: 150
            distance_m:
              type:
                - integer
                - 'null'
              description: |
                Metres between the device fix and the location's configured point.
                Recorded whenever both have coordinates, even with no radius set.
              example: 38957
            within_geofence:
              type:
                - boolean
                - 'null'
              description: |
                Whether the fix falls inside the geofence, with the device's own
                reported accuracy allowed as tolerance. Null when no verdict was
                possible.
              example: false
            verdict:
              type: string
              enum:
                - match
                - mismatch
                - unknown
              example: mismatch
            reason:
              type:
                - string
                - 'null'
              enum:
                - no_device_gps
                - no_location
                - location_without_coordinates
                - no_geofence_radius
                - null
              description: 'Why the verdict is `unknown`. Null otherwise.'
              example: null
        substatus:
          type:
            - object
            - 'null'
          description: |
            The first associated sub-status for this time point (a refinement of the
            main status, for example a specific break type), flattened from the
            related `TempusSubStatus` record together with its display style. Null
            when no sub-status is attached.
          required:
            - id
            - name
            - icon
            - fontcolor
            - backgroundcolor
            - css
            - comment
          properties:
            id:
              type: string
              format: uuid
              description: 'Identifier of the sub-status.'
              example: 550e8400-e29b-41d4-a716-446655440002
            name:
              type:
                - string
                - 'null'
              description: 'Human-readable sub-status name.'
              example: 'Lunch break'
            icon:
              type:
                - string
                - 'null'
              description: |
                CSS icon class used to render the sub-status (from its style's
                `icon_class`). Null when no icon is configured.
              example: 'la la-coffee'
            fontcolor:
              type:
                - string
                - 'null'
              description: |
                Foreground (text) colour for the sub-status label, as a CSS colour
                value (from its style's `font_color`). Null when unset.
              example: '#000000'
            backgroundcolor:
              type:
                - string
                - 'null'
              description: |
                Background colour for the sub-status label, as a CSS colour value
                (from its style's `bg_color`). Null when unset.
              example: '#fff3e0'
            css:
              type: string
              description: |
                Additional CSS class string for the sub-status (from its style's
                `css`, falling back to `css_class`). Empty string when none is
                configured.
              example: substatus-lunch
            comment:
              type: integer
              format: int32
              enum:
                - 0
                - 1
              description: |
                Whether a comment is required when selecting this sub-status: 1 if
                required, 0 otherwise. Derived from the sub-status `meta_data`.
              example: 0
    TempusDepartment:
      type: object
      description: |
        Tempus department as serialized by the V1 `TempusDepartmentResource`.
        Departments are a per-tenant (Pbx) catalog of organizational units used by
        the Tempus time and attendance module. An employee's company context comes
        from their contract; a department is referenced by contracts and may be
        adopted by one or more companies within the tenant.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The `mxvp_user_id` key carries the owning Pbx (tenant)
        identifier. The `flags` and `absence_validation_amount_required` keys are
        fixed compatibility fields emitted with constant values by the current API
        version (an empty string and `0` respectively) and do not vary per record.
      required:
        - id
        - mxvp_user_id
        - name
        - flags
        - absence_validation_amount_required
        - timestamp
        - delete_date
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique department identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this department (the model's
            `pbx_id`). Null for departments that are not bound to a specific tenant.
          example: 550e8400-e29b-41d4-a716-446655440001
        name:
          type: string
          description: 'Display name of the department.'
          example: 'Customer Support'
        flags:
          type: string
          description: |
            Reserved compatibility field. The current API version always emits an
            empty string. Integrators should not rely on this field carrying data.
          example: ''
        absence_validation_amount_required:
          type: integer
          format: int32
          description: |
            Reserved compatibility field indicating the number of absence
            validations required. The current API version always emits `0`.
          example: 0
        timestamp:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Timestamp when the department was last updated (the model's
            `updated_at`). Null when the record has never been persisted with a
            timestamp.
          example: '2024-03-01T08:29:07Z'
          readOnly: true
        delete_date:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Soft-delete timestamp (the model's `deleted_at`). Null for active
            departments; set to the deletion time when the department has been
            soft-deleted.
          example: null
          readOnly: true
    TempusDepartmentBasic:
      type: object
      description: |
        Tempus department as serialized by the V1 `DepartmentResource`.

        Departments are a per-tenant (Pbx) catalog of organizational units used by
        the Tempus time and attendance module. An employee's company context comes
        from their contract; a department is referenced by contracts and may be
        adopted by one or more companies within the tenant.

        This is the properly named representation returned by the `departments`
        endpoint. It exposes only the meaningful fields (id, name, description). The
        legacy `groups` endpoint (schema `TempusDepartment`) returns the same records
        under legacy key names and is kept for backward compatibility only.
      required:
        - id
        - name
        - description
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique department identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        name:
          type: string
          description: 'Display name of the department.'
          example: 'Customer Support'
        description:
          type:
            - string
            - 'null'
          description: 'Optional free-text description of the department.'
          example: 'Handles inbound customer requests'
    TempusUser:
      type: object
      description: |
        Tempus user (time-and-attendance employee) as serialized by the V1
        `TempusUserResource`. Each record represents one `TempusEmployee` belonging to
        a single Pbx (tenant) and is linked to an optional Voxbi `User` account, from
        which the email, name, and telephony extension are resolved.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Name fields fall back to the linked user's values when the
        employee record itself does not carry them: `first_name`, `last_name`, and
        `full_name` are taken from the employee where set, otherwise from the linked
        user. `email` and `ext_number` are always sourced from the linked user and its
        first extension, so they are null when no user (or no extension) is linked.

        `ext_id` is resolved through a helper: it is the identifier of the extension
        belonging to the linked user when one exists, and otherwise falls back to the
        employee's own identifier. It is therefore always a non-null string.

        The `soop_*` fields are legacy placeholders carried over from the previous
        time-tracking system (SOOP). They are currently always null and are returned
        only for backward compatibility with older integrations.
      required:
        - ext_id
        - pbx_id
        - ext_number
        - first_name
        - last_name
        - full_name
        - email
        - soop_enable
        - soop_name
        - soop_badge
      properties:
        ext_id:
          type: string
          format: uuid
          description: |
            Identifier used to address this user on the telephony stack. Resolves to
            the identifier of the extension owned by the linked Voxbi user when one
            exists; otherwise it falls back to the Tempus employee identifier. Always
            present.
          readOnly: true
          example: 550e8400-e29b-41d4-a716-446655440000
        pbx_id:
          type: string
          format: uuid
          description: 'Identifier of the Pbx (tenant) that owns this Tempus employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
        ext_number:
          type:
            - string
            - 'null'
          description: |
            Dialable extension number of the linked user's first extension. Null when
            the employee has no linked user or that user has no extension.
          example: '101'
        first_name:
          type:
            - string
            - 'null'
          description: |
            Given name of the employee. Taken from the employee record when set,
            otherwise from the linked Voxbi user. Null when neither provides a value.
          example: Jane
        last_name:
          type:
            - string
            - 'null'
          description: |
            Family name of the employee. Taken from the employee record when set,
            otherwise from the linked Voxbi user. Null when neither provides a value.
          example: Smith
        full_name:
          type:
            - string
            - 'null'
          description: |
            Computed display name of the employee. Derived from the employee's first
            and last name (ordered per the Pbx name-display preference), falling back
            to the linked user's name. Null when no name is available.
          readOnly: true
          example: 'Jane Smith'
        email:
          type:
            - string
            - 'null'
          format: email
          description: |
            Email address of the linked Voxbi user, used as that user's login
            identifier. Null when the employee has no linked user.
          example: jane.smith@example.com
        soop_enable:
          type:
            - integer
            - 'null'
          format: int32
          description: |
            Legacy SOOP badge-enabled flag (1 enabled, 0 disabled), retained for
            backward compatibility. Currently always null.
          example: null
        soop_name:
          type:
            - string
            - 'null'
          description: |
            Legacy SOOP badge name, retained for backward compatibility. Currently
            always null.
          example: null
        soop_badge:
          type:
            - string
            - 'null'
          description: |
            Legacy SOOP badge data (the encoded badge value), retained for backward
            compatibility. Currently always null.
          example: null
    TempusUserProfile:
      type: object
      description: |
        Tempus user profile for a single employee linked to a Voxbi Cockpit user: the
        company on their active contract, absence (holiday) balances, home office
        allowance, and overtime calculation period. It is assembled in memory by the
        controller (not a single Eloquent model), so the field set is fixed and
        documented below.

        Duration values in the absence summary and the overtime `compensatory_balance`
        are zero-padded `HH:MM:SS` strings where the hours component may exceed 24 (for
        example "120:00:00") and may carry a leading minus sign for negative balances.
        Home office counters (`allowed`, `taken`, `remaining`) are integers in whole
        days. Overtime accrual (`current_accrual.business` / `current_accrual.non_working`)
        is in seconds.

        The optional feature blocks (`home_office`, `overtime`, `travel_time`) always
        carry an `enabled` flag; their detail fields are present only when enabled.

        `travel_time_allowed` is a flat mirror of `travel_time.enabled`, kept for app
        clients that read the flag directly. Both are always present and always agree.

        There are two validator-facing blocks, in opposite directions: `validator` is what
        this employee may approve (null when they are not a validator), and `validators` is
        who approves this employee (always an array, empty when nobody does).

        Note: when the requested employee has no active contract, the endpoint returns
        HTTP 422 with a `{ "message": ... }` body instead of this shape.
      required:
        - employee
        - company
        - contract
        - absence
        - home_office
        - overtime
        - travel_time
        - travel_time_allowed
        - preferences
        - validator
        - validators
      properties:
        employee:
          type: object
          description: 'Basic identity details of the linked Tempus employee.'
          required:
            - full_name
            - email
          properties:
            full_name:
              type: string
              description: "Full name of the employee, falling back to the linked user's name."
              example: 'Jane Smith'
            email:
              type: string
              format: email
              description: 'Email address of the linked user account.'
              example: jane.smith@example.com
        company:
          type: object
          description: "The company on the employee's active contract."
          required:
            - id
            - name
          properties:
            id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'Identifier of the company. Null when the contract has no company.'
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type:
                - string
                - 'null'
              description: 'Display name of the company. Null when the contract has no company.'
              example: 'Acme Corp'
        contract:
          type: object
          description: "The employee's active employment contract dates."
          required:
            - start
            - end
          properties:
            start:
              type:
                - string
                - 'null'
              format: date
              description: 'Start date of the active contract (a date, no time component).'
              example: '2024-01-01'
            end:
              type:
                - string
                - 'null'
              format: date
              description: 'End date of the active contract; null for an open-ended contract.'
              example: null
            department_id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'UUID of the department on the active contract, or null when none is set.'
              example: 550e8400-e29b-41d4-a716-446655440042
        absence:
          type: object
          description: 'Holiday and absence balances for the current calendar year, each an `HH:MM:SS` duration string. Always present.'
          required:
            - possible
            - taken
            - remaining
          properties:
            possible:
              type: string
              description: 'Total holiday entitlement available for the year.'
              example: '200:00:00'
            taken:
              type: string
              description: 'Holiday already consumed during the year.'
              example: '80:00:00'
            remaining:
              type: string
              description: 'Holiday still available to take.'
              example: '120:00:00'
        home_office:
          type: object
          description: |
            Home office allowance for the current year. `allowed`, `taken` and
            `remaining` (whole days) are present only when `enabled` is true.
          required:
            - enabled
          properties:
            enabled:
              type: boolean
              description: "Whether home office is enabled for the employee's company."
              example: true
            allowed:
              type: integer
              format: int32
              description: 'Present only when enabled. Yearly allowance in days (the contract `ho_balance` override, else the company yearly cap).'
              example: 20
            taken:
              type: integer
              format: int32
              description: 'Present only when enabled. Approved home office already taken this year, in whole days.'
              example: 5
            remaining:
              type: integer
              format: int32
              description: 'Present only when enabled. Allowance still available, in whole days (`allowed` - `taken`). May be negative.'
              example: 15
        overtime:
          type: object
          description: |
            Overtime calculation period summary. When `enabled` is false, only the
            `enabled` flag is present. When enabled, the additional fields below are
            included; `current_period` and `current` appear only when a period is
            active for the current date.
          required:
            - enabled
          properties:
            enabled:
              type: boolean
              description: "Whether overtime calculation periods are configured for the employee's company."
              example: true
            decision_enabled:
              type: boolean
              description: 'Present only when enabled. Whether overtime decisions are configured for the company.'
              example: true
            compensatory_balance:
              type: string
              description: |
                Present only when enabled. Employee compensatory balance for the company, `HH:MM:SS` (may be negative). This is the AVAILABLE balance: the snapshot from the last LOCKED period. The running period's undecided accrual is reported separately under `current_accrual`, never folded in here.
              example: '12:30:00'
            compensatory_balance_seconds:
              type: integer
              format: int32
              description: 'Same balance in seconds, so the client does not have to parse the string.'
              example: 45000
            decision_preference:
              type:
                - object
                - 'null'
              description: |
                Present only when enabled. The employee's effective overtime decision
                preference: their own active preference, else the company's. Null when
                none is configured, in which case the company auto-decision policy
                applies at period end. `level` reports which of the two the values
                came from.
              required:
                - level
                - preferred_decision
                - auto_decision_policy
                - max_seconds
                - rest_policy
                - policy_reason
              properties:
                level:
                  type: string
                  enum:
                    - employee
                    - company
                  description: "Whether these values come from the employee's own preference or the inherited company default."
                  example: employee
                preferred_decision:
                  type:
                    - string
                    - 'null'
                  enum:
                    - pay_up_to
                    - increment_up_to
                    - null
                  description: 'The default action for overtime (pay it out up to the cap, or add it to the balance up to the cap). Null when unset.'
                  example: increment_up_to
                auto_decision_policy:
                  type:
                    - string
                    - 'null'
                  enum:
                    - skip_if_manual_decision
                    - force_auto_decision
                    - force_zero_overtime
                    - null
                  description: 'What the system does at period end when the employee makes no manual decision.'
                  example: skip_if_manual_decision
                max_seconds:
                  type:
                    - integer
                    - 'null'
                  format: int32
                  description: 'Cap in seconds that the preferred decision applies up to (for example 36000 = 10 hours). Null when uncapped.'
                  example: 36000
                rest_policy:
                  type:
                    - string
                    - 'null'
                  enum:
                    - add_to_balance
                    - drop
                    - null
                  description: 'What happens to overtime beyond the cap (carry it to the balance or drop it). Null when unset.'
                  example: add_to_balance
                policy_reason:
                  type:
                    - string
                    - 'null'
                  description: 'Free-text justification recorded with the preference. Null when none was given.'
                  example: 'Per HR overtime policy.'
            current_period:
              type: object
              description: 'The overtime calculation period containing the current date. Present only when enabled and an active period exists.'
              required:
                - id
                - start
                - end
                - decision_possible_from
                - decision_possible_to
              properties:
                id:
                  type: string
                  format: uuid
                  description: 'Identifier of the overtime period.'
                  example: 550e8400-e29b-41d4-a716-446655440000
                start:
                  type: string
                  format: date
                  description: 'First day of the overtime period.'
                  example: '2026-01-01'
                end:
                  type: string
                  format: date
                  description: 'Last day of the overtime period.'
                  example: '2026-12-31'
                decision_possible_from:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: 'First day the employee may submit an overtime decision. Null when decisions are not enabled.'
                  example: '2026-12-24'
                decision_possible_to:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: 'Last day the employee may submit an overtime decision. Null when decisions are not enabled.'
                  example: '2026-12-31'
            current_accrual:
              type: object
              description: |
                Overtime accrued within the current period through the last COMPLETED day, split by day type. Always present (zeros when no period is open). Every figure is a signed BALANCE in seconds, with a pre-formatted `HH:MM:SS` twin and a ready-made `total`, so a client can display it as-is or convert.

                The range ends at YESTERDAY midnight — today is never counted. Today is still being lived, and the calculation charges the full workshift requirement against however much has been worked so far, so including it would show the rest of the day as undertime and make the figure climb hour by hour. Only finished days are stable enough to report as an accrued balance.

                Every overtime surface uses this same cutoff — this endpoint, `GET /{pbx_id}/user/{employee_id}/user-overtime-decision/getOvertime`, and the figure stored when a decision is submitted all report the identical number, so the accrual a client previews is the accrual the decision books.
              required:
                - business
                - business_formatted
                - non_working
                - non_working_formatted
                - total
                - total_formatted
              properties:
                business:
                  type: integer
                  format: int32
                  description: 'Balance accrued on business (working) days, in seconds. Negative when the period is running below the required time.'
                  example: 7200
                business_formatted:
                  type: string
                  description: 'Same figure as `HH:MM:SS`, sign glued to the value (`-02:08:49`). Hours may exceed 24.'
                  example: '02:00:00'
                non_working:
                  type: integer
                  format: int32
                  description: 'Balance accrued on non-working days, in seconds.'
                  example: 3600
                non_working_formatted:
                  type: string
                  description: 'Same figure as `HH:MM:SS`, sign glued to the value.'
                  example: '01:00:00'
                total:
                  type: integer
                  format: int32
                  description: '`business` + `non_working`, in seconds. The figure to display as the period accrual.'
                  example: 10800
                total_formatted:
                  type: string
                  description: 'Same total as `HH:MM:SS`, sign glued to the value.'
                  example: '03:00:00'
        travel_time:
          type: object
          description: |
            Travel time allowance. When `enabled` is false, only the `enabled` flag is
            present. When enabled, the employee may credit extra payable minutes to a
            day through POST /{pbx_id}/user/{employee_id}/travel-time, up to
            `max_per_day` times per date. The minutes are placed where they can actually
            be paid — before the day's first PAYABLE status, after the day's last closed
            row, or into an unpayable break — so they count toward work time and
            overtime. A day with no room for them files the request for HR instead
            (HTTP 202), which is what `pending_today` counts.
          required:
            - enabled
          properties:
            enabled:
              type: boolean
              description: 'Whether travel time is enabled for this employee.'
              example: true
            minutes_per_request:
              type: integer
              format: int32
              description: 'Present only when enabled. Payable minutes credited per request.'
              example: 30
            max_per_day:
              type: integer
              format: int32
              description: 'Present only when enabled. How many credits are allowed per date.'
              example: 1
            used_today:
              type: integer
              format: int32
              description: 'Present only when enabled. Credits already taken today.'
              example: 0
            remaining_today:
              type: integer
              format: int32
              description: 'Present only when enabled. Credits still available today.'
              example: 1
            pending_today:
              type: integer
              format: int32
              description: |
                Present only when enabled. Requests for today filed for HR and not yet accepted — nothing has been credited for these. A second request for a date that already has one is refused with `already_pending`.
              example: 0
        travel_time_allowed:
          type: boolean
          description: |
            Flat mirror of `travel_time.enabled`, for clients that read the flag directly. Always present and always consistent with the block.
          example: true
        preferences:
          type: object
          description: |
            The employee user's Tempus display preferences. These describe how the
            user prefers dates rendered; they do not change the format of any field
            in this response (dates here are always ISO `Y-m-d`). Always present, with
            the user's stored choice or the system default.
          required:
            - date_format
          properties:
            date_format:
              type: string
              enum:
                - d/m/Y
                - m/d/Y
                - Y-m-d
                - d.m.Y
              description: |
                The user's preferred date display format, as a PHP/`date()` format
                string. Falls back to the system default (`Y-m-d`) when the user has
                set no preference. A client can use this to render dates in the user's
                preferred style.
              example: d.m.Y
        validator:
          type:
            - object
            - 'null'
          description: |
            The employee's validator role, or `null` when they hold none. Null is the
            signal for whether to offer a validator section at all; a validator with an
            empty queue today is still a validator, so use `pending` for badges and
            empty states rather than to decide whether the section exists.

            `permissions` answers for both approval engines: the approval chains, and
            the older validator rules while a tenant still has them.

            The `companies`, `departments` and `employees` lists are the roster the older
            rules resolved, and are the values behind the filters for
            `GET /{pbx_id}/validator/employees`. Approval chains cannot produce that
            roster cheaply: a validator's place is a position in each requester's own
            chain, resolved through that person's contract, so for a tenant configured
            only with chains these three lists come back empty. Use `pending` and the
            queue endpoints (`GET /{pbx_id}/validator/pending-requests`,
            `pending-corrections`) instead, which answer from the chain itself.
          required:
            - permissions
            - pending
            - companies
            - departments
            - employees
          properties:
            permissions:
              type: object
              description: 'Which validator modules this employee may act on.'
              properties:
                holiday_requests:
                  type: boolean
                home_office_requests:
                  type: boolean
                time_point_corrections_requests:
                  type: boolean
                schedules_management:
                  type: boolean
            pending:
              type: object
              description: |
                How many requests of each type are waiting on this employee right now,
                counted from the approval rows addressed to them. Keyed the same way as
                `permissions`. `schedules_management` is always 0: schedule assignment is
                direct management, not a request queue.
              properties:
                holiday_requests:
                  type: integer
                  example: 3
                home_office_requests:
                  type: integer
                  example: 1
                time_point_corrections_requests:
                  type: integer
                  example: 0
                schedules_management:
                  type: integer
                  example: 0
            companies:
              type: array
              description: "Distinct companies in the validator's scope."
              items:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
            departments:
              type: array
              description: "Distinct departments in the validator's scope."
              items:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
            employees:
              type: array
              description: 'Lightweight list of the employees the validator may consult.'
              items:
                type: object
                properties:
                  employee_id:
                    type: string
                    format: uuid
                  name:
                    type: string
        validators:
          type: array
          description: |
            The other direction from `validator`: the people who validate THIS employee's
            requests, one entry per validator, with the request types each of them covers.
            Where `validator` says what this employee may approve, `validators` says who
            approves this employee.

            Always present. Empty array when nobody validates the employee. Resolved from the
            older validator rules on the same basis as the `validator` block, so on a tenant
            configured only with approval chains (which cannot answer "who validates me"
            cheaply) it comes back empty; drive off `pending` and the queue endpoints there.
          items:
            type: object
            required:
              - employee_id
              - user_id
              - name
              - scopes
            properties:
              employee_id:
                type: string
                format: uuid
                description: "The validator's Tempus employee id."
                example: 550e8400-e29b-41d4-a716-446655440010
              user_id:
                type:
                  - string
                  - 'null'
                format: uuid
                description: "The validator's linked Cockpit user id, or null when they have no linked user."
                example: 550e8400-e29b-41d4-a716-446655440011
              name:
                type: string
                description: "The validator's display name (the PBX name-order preference is applied)."
                example: 'Jane Smith'
              scopes:
                type: array
                description: |
                  The request types this validator covers for the employee, in a stable order.
                  A validator who covers more than one type appears once with every type listed.
                items:
                  type: string
                  enum:
                    - holiday_requests
                    - home_office_requests
                    - time_point_corrections_requests
                    - schedules_management
                example:
                  - holiday_requests
                  - time_point_corrections_requests
    TempusTravelTimeCredit:
      type: object
      description: |
        One travel time credit: a payable block of minutes added to a day because the
        employee requested it.

        Each credit is stored as an accepted time point correction (the "create a new
        time point" shape) plus the time point it produced, so it appears in the
        employee's correction history and can be corrected or removed like any other
        time point.
      properties:
        id:
          type: string
          format: uuid
          description: 'UUID of the correction row that recorded the request.'
          example: 550e8400-e29b-41d4-a716-446655440010
        date:
          type: string
          format: date
          description: 'The date the credit was applied to.'
          example: '2026-05-11'
        start_time:
          type: string
          description: 'Start of the credited block, `Y-m-d H:i:s`.'
          example: '2026-05-11 07:30:00'
        end_time:
          type:
            - string
            - 'null'
          description: |
            End of the credited block, `Y-m-d H:i:s`. Null only if the produced time point has since been left open by a later correction.
          example: '2026-05-11 08:00:00'
        minutes:
          type:
            - integer
            - 'null'
          format: int32
          description: |
            Length of the credited block in whole minutes. Normally the configured allowance, but smaller when the block had to be clamped to the start of the day. Null when `end_time` is null.
          example: 30
        status_id:
          type: string
          format: uuid
          description: 'UUID of the PBX travel time status the credit was recorded on.'
          example: 550e8400-e29b-41d4-a716-446655440011
        timepoint_id:
          type:
            - string
            - 'null'
          format: uuid
          description: 'UUID of the time point the credit produced.'
          example: 550e8400-e29b-41d4-a716-446655440012
        comment:
          type:
            - string
            - 'null'
          description: 'The comment stored with the credit.'
          example: 'Travel time requested'
        created_at:
          type:
            - string
            - 'null'
          description: 'When the credit was recorded, `Y-m-d H:i:s`.'
          example: '2026-05-11 12:00:00'
    TempusUserCompany:
      type: object
      description: |
        Association between a Tempus employee and a company, as serialized by the V1
        `UserCompanyResource`. Each record is backed by a Tempus contract row and
        describes the employee's participation in one company: their working-time
        balances, contract period, job title, and the company's payroll-relevant
        settings.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Field names are remapped for the integration audience
        (for example the contract `pbx_id` is exposed as `mxvp_user_id`, and the
        contract `job_title` is exposed as `title`). The nested `company` object is
        always present and carries a subset of the related company's fields; its
        scalar values are null when no company is linked.

        Monetary and balance values are normalized in the resource: `participation`
        and `ho_balance` are cast to floating-point numbers, `compensatory_balance`
        is cast to an integer (defaulting to 0 rather than null), and `main_company`
        is emitted as the integer 1 or 0 rather than a boolean.
      required:
        - id
        - mxvp_user_id
        - ext_id
        - company_id
        - participation
        - contract_start
        - contract_end
        - main_company
        - compensatory_balance
        - ho_balance
        - title
        - department_id
        - delete_date
        - company
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the employee-company association (the underlying Tempus contract id).'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: "Identifier of the Pbx (tenant) that owns this association. Maps to the contract's `pbx_id`."
          example: 550e8400-e29b-41d4-a716-446655440001
        ext_id:
          type:
            - string
            - 'null'
          description: |
            External extension identifier resolved for the linked employee, or null
            when the employee has no associated extension.
          example: '1001'
        company_id:
          type:
            - string
            - 'null'
          format: uuid
          description: 'Identifier of the company this association links to. Null when no company is set.'
          example: 550e8400-e29b-41d4-a716-446655440002
        participation:
          type:
            - number
            - 'null'
          format: float
          description: |
            Employee's participation ratio in the company, expressed as a fractional
            value (for example 1.0 for full participation, 0.5 for half). Null when
            not configured.
          example: 1
        contract_start:
          type:
            - string
            - 'null'
          format: date-time
          description: 'Start of the contract period, in ISO 8601 format. Null when not set.'
          example: '2024-01-01T00:00:00.000000Z'
        contract_end:
          type:
            - string
            - 'null'
          format: date-time
          description: 'End of the contract period, in ISO 8601 format. Null for an open-ended contract.'
          example: '2025-12-31T00:00:00.000000Z'
        main_company:
          type: integer
          format: int32
          enum:
            - 0
            - 1
          description: |
            Whether this is the employee's main (primary) company. Emitted as the
            integer 1 when true and 0 when false.
          example: 1
        compensatory_balance:
          type: integer
          format: int32
          description: |
            Accrued compensatory time balance for the employee, in seconds. Defaults
            to 0 when no balance is recorded (never null).
          example: 3600
        ho_balance:
          type:
            - number
            - 'null'
          format: float
          description: |
            Home-office (remote work) balance for the employee, expressed in the
            configured balance unit. Null when not tracked.
          example: 8.5
        title:
          type:
            - string
            - 'null'
          description: "Job title held by the employee under this contract. Maps to the contract's `job_title`. Null when unset."
          example: 'Sales Representative'
        department_id:
          type:
            - string
            - 'null'
          format: uuid
          description: 'Identifier of the department the employee belongs to within the company. Null when unassigned.'
          example: 550e8400-e29b-41d4-a716-446655440003
        delete_date:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Soft-deletion timestamp of the association, in ISO 8601 format. Null when
            the association is active (not deleted).
          example: null
        company:
          type: object
          description: |
            Subset of the linked company's details. Always present as an object; its
            scalar fields are null when no company is associated with this contract.
          required:
            - id
            - mxvp_user_id
            - company
            - address
            - country_cc
            - legalHolidays
            - full_time
            - salary_lu_id
            - overtime_calculation_period_enabled
            - overtime_decision_enabled
            - delete_date
          properties:
            id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'Unique identifier of the company. Null when no company is linked.'
              example: 550e8400-e29b-41d4-a716-446655440002
            mxvp_user_id:
              type:
                - string
                - 'null'
              format: uuid
              description: "Identifier of the Pbx (tenant) that owns the company. Maps to the company's `pbx_id`."
              example: 550e8400-e29b-41d4-a716-446655440001
            company:
              type:
                - string
                - 'null'
              description: "Display name of the company. Maps to the company's `name`. Null when no company is linked."
              example: 'Sales Team'
            address:
              type:
                - string
                - 'null'
              description: |
                Single-line postal address composed of the company's street, postal
                code, and city (joined by spaces). Null when none of those parts are
                set.
              example: '100 Market Street 10001 New York'
            country_cc:
              type:
                - string
                - 'null'
              description: "ISO country code of the company's country. Null when no country is set."
              example: US
            legalHolidays:
              type:
                - number
                - 'null'
              format: float
              description: |
                Number of legally mandated paid leave days granted per year. Maps to
                the company's `legal_paid_leaves_yearly_days`. Null when not
                configured.
              example: 26
            full_time:
              type:
                - integer
                - 'null'
              format: int32
              description: |
                Full-time working time reference for the company, expressed in
                seconds. Maps to the company's `full_time_seconds`. Null when no
                company is linked.
              example: 144000
            salary_lu_id:
              type: 'null'
              description: |
                Reserved field for a salary lookup identifier. Currently always null
                (not yet populated by the API).
              example: null
            overtime_calculation_period_enabled:
              type: boolean
              description: 'Whether overtime is calculated over a defined accounting period for this company. Defaults to false.'
              example: false
            overtime_decision_enabled:
              type: boolean
              description: 'Whether overtime requires explicit approval (decision) for this company. Defaults to false.'
              example: false
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: 'Soft-deletion timestamp of the company, in ISO 8601 format. Null when the company is active.'
              example: null
    TempusHomeOfficeCalendar:
      type: object
      description: |
        Virtual home office calendar entry for a single employee and calendar year, as
        serialized by the V1 `HomeOfficeCalendarResource`. This object is not backed by
        a dedicated table: it is derived on the fly from `TempusTransaction` records of
        type `home_office`, then grouped by employee, company, and year. The response
        shape is preserved for backward compatibility with the legacy
        `TempusHomeOfficeCalendar` resource, so several values are denormalized into
        this single object rather than exposed as relations.

        Each day a home office request touches is classified into one of three date
        lists based on the source transaction's status and sub-type: pending requests
        go into `requested_days`, approved requests into `approved_days`, and pending
        removals or rejected requests into `removed_days`. Every date is an ISO 8601
        calendar date (YYYY-MM-DD) and the lists are deduplicated. The matching
        `count_*` fields hold the number of entries in each list.

        The `user` object is only present when the calendar is requested with employee
        user details included (the `includeUser` option); it is absent otherwise.
      required:
        - id
        - mxvp_user_id
        - ext_id
        - company_id
        - creator_id
        - validator_id
        - year
        - days_of_week
        - requested_days
        - approved_days
        - removed_days
        - comment
        - created
        - modified
        - count_requested_days
        - count_approved_days
        - count_removed_days
      properties:
        id:
          type: string
          format: uuid
          description: |
            Identifier of the underlying `TempusTransaction` (home office request) that
            seeded this calendar entry. Not a stable identifier of the calendar itself,
            which is a virtual aggregate.
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this calendar. Named `mxvp_user_id`
            for backward compatibility with the legacy API; it corresponds to the
            transaction's `pbx_id`.
          example: 550e8400-e29b-41d4-a716-446655440001
        ext_id:
          type:
            - string
            - 'null'
          description: |
            External identifier of the employee's primary extension, resolved from the
            employee record. Null when the employee has no associated extension.
          example: '201'
        company_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the company the home office requests belong to. Null when the
            requests are not scoped to a specific company.
          example: 550e8400-e29b-41d4-a716-446655440002
        creator_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus employee who created the home office request
            (the transaction requester, falling back to the subject employee). This is
            a `tempus_employees` identifier, not a user identifier.
          example: 550e8400-e29b-41d4-a716-446655440003
        validator_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus employee who validated (approved) the request,
            resolved from the approving user. Null when the request has not yet been
            validated. This is a `tempus_employees` identifier, not a user identifier.
          example: 550e8400-e29b-41d4-a716-446655440004
        year:
          type: integer
          format: int32
          description: |
            Calendar year this entry aggregates. All dates in the day lists fall within
            this year.
          example: 2026
        days_of_week:
          type: string
          description: |
            Comma-separated list of weekday abbreviations on which home office is
            considered applicable. Currently a fixed working-week value.
          example: 'mon,tue,wed,thu,fri'
        requested_days:
          type: array
          description: |
            Calendar dates with a pending home office request (not yet approved). Each
            entry is an ISO 8601 date (YYYY-MM-DD). Deduplicated; may be empty.
          items:
            type: string
            format: date
            example: '2026-06-15'
        approved_days:
          type: array
          description: |
            Calendar dates on which home office has been approved. Each entry is an
            ISO 8601 date (YYYY-MM-DD). Deduplicated; may be empty.
          items:
            type: string
            format: date
            example: '2026-06-16'
        removed_days:
          type: array
          description: |
            Calendar dates that were removed: pending removals or rejected requests.
            Each entry is an ISO 8601 date (YYYY-MM-DD). Deduplicated; may be empty.
          items:
            type: string
            format: date
            example: '2026-06-17'
        comment:
          type: string
          description: |
            Free-form note carried over from the most recent contributing home office
            transaction. Empty string when no note was provided.
          example: 'Working from home on project deadline week'
        created:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            ISO 8601 timestamp when the seeding transaction was created. Null when the
            timestamp is unavailable.
          example: '2026-06-01T08:29:07+00:00'
          readOnly: true
        modified:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            ISO 8601 timestamp when the seeding transaction was last updated. Null when
            the timestamp is unavailable.
          example: '2026-06-10T14:12:33+00:00'
          readOnly: true
        count_requested_days:
          type: integer
          format: int32
          description: 'Number of distinct dates in `requested_days`.'
          example: 1
        count_approved_days:
          type: integer
          format: int32
          description: 'Number of distinct dates in `approved_days`.'
          example: 1
        count_removed_days:
          type: integer
          format: int32
          description: 'Number of distinct dates in `removed_days`.'
          example: 1
        user:
          type: object
          description: |
            Summary of the employee's linked Voxbi user. Only present when the calendar
            is requested with user details included; omitted otherwise.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the linked user.'
              example: 550e8400-e29b-41d4-a716-446655440005
            number:
              type:
                - string
                - 'null'
              description: 'Extension number assigned to the user. Null when none is set.'
              example: '201'
            name:
              type:
                - string
                - 'null'
              description: 'First name of the user.'
              example: Jane
            name2:
              type:
                - string
                - 'null'
              description: 'Last name of the user.'
              example: Smith
    TempusPublicHoliday:
      type: object
      description: |
        Tempus public holiday as serialized by the V1 `TempusPublicHolidayResource`.
        A public holiday marks a non-working (or partially non-working) day used by the
        Tempus time and attendance module when computing worked hours, leave, and pay.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Two fields are renamed or derived on output: the tenant
        identifier is exposed as `mxvp_user_id` (falling back to the authenticated
        caller's PBX when the holiday has no own `pbx_id`), and the model `duration`
        column is exposed as `halfday`. The `country_cc` value is the ISO 3166-1
        alpha-2 code resolved from the related `Country` record. Date and timestamp
        values are emitted as ISO 8601 strings.
      required:
        - id
        - name
        - date
        - halfday
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique public holiday identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this public holiday. Sourced from
            the holiday's own `pbx_id` and, when that is absent, from the authenticated
            caller's PBX. Null only when neither the holiday nor the caller resolves to
            a PBX.
          example: 550e8400-e29b-41d4-a716-446655440001
        name:
          type: string
          description: 'Human-readable name of the public holiday.'
          example: "New Year's Day"
        date:
          type: string
          format: date-time
          description: |
            Calendar date of the public holiday, emitted as an ISO 8601 timestamp at
            the start of that day in the application timezone.
          example: '2024-01-01T00:00:00+00:00'
        halfday:
          type: string
          enum:
            - fullday
            - halfam
            - halfpm
          description: |
            Portion of the day the holiday applies to: `fullday` for an entire
            non-working day, `halfam` for a non-working morning, and `halfpm` for a
            non-working afternoon.
          example: fullday
        country_cc:
          type:
            - string
            - 'null'
          minLength: 2
          maxLength: 2
          description: |
            ISO 3166-1 alpha-2 country code of the holiday's associated country (for
            example `LU` or `US`), resolved from the related `Country` record. Null
            when the holiday is not linked to a country.
          example: US
        delete_date:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Soft-delete timestamp, emitted as an ISO 8601 string. Null for active
            holidays; populated only when the holiday has been soft-deleted and is
            returned in a trashed listing.
          example: null
          readOnly: true
    TempusOvertimeCalculationPeriod:
      type: object
      description: |
        A Tempus overtime calculation period as serialized by the V1
        `OvertimeCalculationPeriodResource`. An overtime period defines a bounded
        window (`start` to `end`) over which an employee's overtime balance is
        accumulated and, once finalized, locked against further changes.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The `ext_id` field is resolved dynamically: it prefers the
        telephony extension identifier of the linked employee and falls back to the
        underlying user identifier when no extension is linked. The `locked` flag is
        derived from the period's status (true only when the status is `locked`), and
        `delete_date` reflects the soft-delete timestamp (the period is normally only
        present in responses while not deleted).

        Timestamp fields (`start`, `end`, `delete_date`) are serialized as ISO 8601
        strings in UTC.
      required:
        - id
        - mxvp_user_id
        - company_id
        - ext_id
        - start
        - end
        - locked
        - delete_date
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the overtime calculation period.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this period. Mirrors the model's
            `pbx_id` column, exposed under the integration-facing `mxvp_user_id` name.
          example: 550e8400-e29b-41d4-a716-446655440001
        company_id:
          type: string
          format: uuid
          description: 'Identifier of the Tempus company this period belongs to.'
          example: 550e8400-e29b-41d4-a716-446655440002
        ext_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            External reference for the employee the period applies to. Resolved to the
            telephony extension identifier of the linked employee when one exists,
            otherwise falling back to the underlying user identifier. Null when the
            period is not associated with any user.
          example: 550e8400-e29b-41d4-a716-446655440003
        start:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Start of the overtime calculation window, serialized as an ISO 8601
            UTC timestamp. Null when no start date is set.
          example: '2024-03-01T00:00:00.000000Z'
        end:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            End of the overtime calculation window, serialized as an ISO 8601
            UTC timestamp. Null when no end date is set.
          example: '2024-03-31T00:00:00.000000Z'
        locked:
          type: boolean
          description: |
            Whether the period is locked. True only when the period's status is
            `locked`, meaning its overtime balance is finalized and no longer editable.
            False for all other statuses (draft, open, ongoing, processed).
          example: false
        delete_date:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Soft-delete timestamp, serialized as an ISO 8601 UTC timestamp. Null for
            active (non-deleted) periods, which is the usual case in API responses.
          example: null
    TempusUserOvertimeDecision:
      type: object
      description: |
        A single overtime decision recorded against an employee for a given overtime
        calculation period. A decision captures how an employee's accrued overtime
        balance is resolved: how much is paid out, converted, reset, or carried
        forward, together with the resulting new balance.

        All duration fields (`decision_balance`, `decision_overtime`, `to_pay`,
        `to_increment`, `to_convert`, `to_reset`, `decision_new_balance`) are
        expressed as a whole number of seconds. They are returned as raw integer
        second counts, not as the HHH:MM display strings used in the admin UI.

        The related calculation period is only present in the response under
        `overtime_calculation_period` when it has been explicitly loaded by the
        endpoint (eager loaded); otherwise the field is omitted.

        **Rows for a period that is still running are computed live.** An employee
        decides once, part-way through the period, and then keeps working, so the
        figures stored on the row are a snapshot of that moment and go out of date
        immediately. On `GET /{pbx_id}/user/{employee_id}/user-overtime-decision`,
        such a row therefore reports `decision_balance`, `decision_overtime`,
        `to_increment` and `decision_new_balance` as they stand right now, against the
        decision the employee made, and `values_live` is true. Settled history — a
        processed row, or any row whose period has ended — is returned exactly as
        stored. See `values_live` below.
      required:
        - id
        - mxvp_user_id
        - ext_id
        - overtime_calculation_period_id
        - decision_type
        - decision
        - decision_balance
        - decision_overtime
        - to_pay
        - to_pay_extra
        - to_increment
        - to_convert
        - to_reset
        - decision_new_balance
        - comment
        - locked
        - values_live
        - created
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the overtime decision.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: 'Identifier of the Pbx (tenant) that owns this decision.'
          example: 550e8400-e29b-41d4-a716-446655440001
        ext_id:
          type:
            - string
            - 'null'
          description: |
            External extension identifier of the employee the decision applies to,
            resolved from the employee record. Null when the employee has no
            associated extension.
          example: '1042'
        overtime_calculation_period_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the overtime calculation period this decision belongs to.
            Null when the decision is not linked to a specific period.
          example: 550e8400-e29b-41d4-a716-446655440002
        decision_type:
          type: string
          enum:
            - manual
            - automatic
          description: |
            How the decision was created. Defaults to `manual` when not otherwise
            set. `manual` decisions are entered by an operator, `automatic` decisions
            are produced by the system.
          example: manual
        decision:
          type:
            - string
            - 'null'
          description: |
            The chosen resolution applied to the employee's overtime balance for the
            period (for example whether the overtime is paid out, converted, or
            reset). Null when no resolution has been selected yet.
          example: pay_out
        decision_balance:
          type: integer
          format: int32
          description: |
            The employee's overtime balance, in seconds, carried into this period:
            the `decision_new_balance` of the last LOCKED period, or the contract's
            opening base when nothing has been locked yet. Maps to the model's
            `old_balance`.
          example: 36000
        decision_overtime:
          type: integer
          format: int32
          description: |
            The overtime accrued during the period, in seconds, that this decision
            resolves. Counted over COMPLETED days only — the range ends at yesterday
            midnight, so neither the remaining workdays nor the hours still owed on
            today are counted as undertime. (A day carries its full shift requirement
            from the moment it begins, so a day in progress always reads negative.)
            Negative when the employee genuinely worked less than required over those
            completed days. Maps to the model's `overtime`.

            On a running period this is recomputed per request and keeps moving until
            the period closes; see `values_live`.
          example: 7200
        to_pay:
          type: integer
          format: int32
          description: |
            Amount of overtime, in seconds, to be paid out to the employee. Never
            negative and never more than `decision_balance + decision_overtime`.

            This is the employee's own commitment to cash out a given amount, so it is
            NOT re-derived on a live row even as the accrual grows — it is only clamped
            down if it would exceed what is available. The growth lands on
            `to_increment` instead.
          example: 3600
        to_pay_extra:
          type: integer
          format: int32
          description: |
            Additional overtime to pay out, in seconds. Always returned as 0 by this
            endpoint (reserved for future use).
          example: 0
        to_increment:
          type: integer
          format: int32
          description: |
            Amount of overtime, in seconds, added to the employee's balance:
            `decision_overtime - to_pay`. Negative when the payout is larger than the
            period's accrual (the difference is drawn from the carried-in balance), or
            when the period itself ended in undertime.
          example: 0
        to_convert:
          type: integer
          format: int32
          description: |
            Amount of overtime, in seconds, to be converted (for example into leave
            or another balance type).
          example: 1800
        to_reset:
          type: integer
          format: int32
          description: 'Amount of overtime, in seconds, to be reset (discarded) from the balance.'
          example: 0
        decision_new_balance:
          type: integer
          format: int32
          description: |
            The resulting overtime balance, in seconds, after applying this decision —
            what the employee has left once the payout is taken out. Derived by the
            system as
            `decision_balance + decision_overtime - to_pay - to_convert - to_reset`.
            Maps to the model's `new_balance`.
          example: 38400
        comment:
          type:
            - string
            - 'null'
          description: 'Optional free-form note explaining or justifying the decision.'
          example: "Carried forward at the employee's request"
        locked:
          type: boolean
          description: |
            Whether the decision has been processed and locked. True once the
            decision has a processing timestamp, after which it should be treated as
            final and immutable.
          example: false
        values_live:
          type: boolean
          description: |
            Whether the duration fields on this row were computed just now rather than
            read from the decision snapshot.

            True only for a row whose period is still running and which has not been
            processed. Those figures are a moving target — they change as the employee
            keeps working, and are final only once the period closes and the decision
            is locked. False for all settled history, where the stored values are
            returned verbatim.
          example: false
        created:
          type:
            - string
            - 'null'
          description: |
            Timestamp when the decision was created, formatted as `Y-m-d H:i:s`
            (for example `2024-03-01 08:29:07`). Null when the creation timestamp is
            not set.
          example: '2024-03-01 08:29:07'
          readOnly: true
        overtime_calculation_period:
          type: object
          description: |
            The related overtime calculation period this decision belongs to. Only
            present when the relation has been eager loaded by the endpoint;
            otherwise the field is omitted from the response.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the overtime calculation period.'
              example: 550e8400-e29b-41d4-a716-446655440002
              readOnly: true
            mxvp_user_id:
              type: string
              format: uuid
              description: 'Identifier of the Pbx (tenant) that owns the period.'
              example: 550e8400-e29b-41d4-a716-446655440001
            company_id:
              type:
                - string
                - 'null'
              format: uuid
              description: 'Identifier of the Tempus company the period belongs to.'
              example: 550e8400-e29b-41d4-a716-446655440003
            ext_id:
              type:
                - string
                - 'null'
              description: |
                External extension identifier of the employee, falling back to the
                period's user identifier when the employee has no extension.
              example: '1042'
            start:
              type:
                - string
                - 'null'
              format: date-time
              description: 'ISO 8601 timestamp marking the start of the calculation period.'
              example: '2024-03-01T00:00:00Z'
            end:
              type:
                - string
                - 'null'
              format: date-time
              description: 'ISO 8601 timestamp marking the end of the calculation period.'
              example: '2024-03-31T23:59:59Z'
            locked:
              type: boolean
              description: 'Whether the calculation period is locked and no longer editable.'
              example: false
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                ISO 8601 timestamp when the period was soft deleted. Null while the
                period is active.
              example: null
    TempusOvertimeDecisionPreference:
      type: object
      description: |
        The employee level overtime decision preference: the standing rule that tells
        the nightly overtime job what to do with the overtime this employee produces.

        It is the same row HR edits on the employee record under "Decision
        Preferences", stored in `tempus_overtime_decision_preferences`. An employee
        has at most one of these. When it is absent the company level preference
        applies instead.

        When `auto_decision_policy` is `force_zero_overtime` the employee is not
        eligible for overtime at all, so `preferred_decision`, `max_seconds` and
        `rest_policy` are always null.
      properties:
        id:
          type: string
          format: uuid
          description: 'UUID of the preference row.'
          example: 9b1f0c62-4d0a-4e2f-9f43-6f4a5c8d1e70
        scope:
          type: string
          enum:
            - employee
          description: 'Always `employee` on this endpoint. Company level rows are managed by HR only.'
          example: employee
        employee_id:
          type: string
          format: uuid
          description: 'UUID of the employee the preference belongs to.'
          example: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
        auto_decision_policy:
          type: string
          enum:
            - skip_if_manual_decision
            - force_auto_decision
            - force_zero_overtime
          description: |
            How the automatic overtime decision behaves.

            | value | meaning |
            |---|---|
            | `skip_if_manual_decision` | Leave the period alone when a manual decision already exists. |
            | `force_auto_decision` | Always apply the automatic decision, overriding a manual one. |
            | `force_zero_overtime` | The employee is not eligible for overtime. |
          example: force_auto_decision
        auto_decision_policy_label:
          type: string
          description: 'Human readable label for `auto_decision_policy`, translated to the request locale.'
          example: 'Force auto-decision (override manual)'
        policy_reason:
          type:
            - string
            - 'null'
          maxLength: 1000
          description: 'Free text note explaining why this policy was chosen.'
          example: 'Prefers time off over payout'
        preferred_decision:
          type:
            - string
            - 'null'
          enum:
            - pay_up_to
            - increment_up_to
            - null
          description: |
            What to do with the overtime, up to the `max_seconds` cap. Null when
            `auto_decision_policy` is `force_zero_overtime`.

            | value | meaning |
            |---|---|
            | `pay_up_to` | Pay the overtime out, up to the cap. |
            | `increment_up_to` | Add the overtime to the compensatory balance, up to the cap. |
          example: pay_up_to
        preferred_decision_label:
          type:
            - string
            - 'null'
          description: 'Human readable label for `preferred_decision`.'
          example: 'Pay up to X hours'
        max_seconds:
          type:
            - integer
            - 'null'
          format: int32
          minimum: 3600
          maximum: 115200
          description: |
            The cap in seconds, from 3600 (1 hour) to 115200 (32 hours). Null when `auto_decision_policy` is `force_zero_overtime`.
          example: 28800
        max_hours:
          type:
            - number
            - 'null'
          format: float
          description: 'The same cap expressed in hours, rounded to two decimals. Convenience mirror of `max_seconds`.'
          example: 8
        rest_policy:
          type:
            - string
            - 'null'
          enum:
            - add_to_balance
            - drop
            - null
          description: |
            What happens to the overtime left over above the cap. Null when
            `auto_decision_policy` is `force_zero_overtime`.

            | value | meaning |
            |---|---|
            | `add_to_balance` | Carry the remainder into the compensatory balance. |
            | `drop` | Discard the remainder. |
          example: add_to_balance
        rest_policy_label:
          type:
            - string
            - 'null'
          description: 'Human readable label for `rest_policy`.'
          example: 'Add to balance'
        is_active:
          type: boolean
          description: 'Whether the preference is applied. A deactivated row is kept but ignored.'
          example: true
        created_at:
          type:
            - string
            - 'null'
          description: 'When the preference was first saved, `Y-m-d H:i:s`.'
          example: '2026-08-06 09:14:22'
        updated_at:
          type:
            - string
            - 'null'
          description: 'When the preference was last changed, `Y-m-d H:i:s`.'
          example: '2026-08-06 10:02:51'
    TempusOvertimeDecisionPreferenceMeta:
      type: object
      description: |
        Everything a client needs to render the preference form without hardcoding the enums: the selectable values with their translated labels, the bounds of the cap, and the values that apply when the employee has never saved a preference.
      required:
        - configured
        - options
        - limits
        - defaults
      properties:
        configured:
          type: boolean
          description: 'Whether an employee level preference row exists. False means `data` is null and the company level rule applies.'
          example: true
        options:
          type: object
          description: 'Selectable values keyed by field name. Each entry maps the stored value to its translated label.'
          required:
            - auto_decision_policy
            - preferred_decision
            - rest_policy
          properties:
            auto_decision_policy:
              type: object
              additionalProperties:
                type: string
              example:
                skip_if_manual_decision: 'Skip if manual decision exists'
                force_auto_decision: 'Force auto-decision (override manual)'
                force_zero_overtime: 'Force zero overtime (not eligible)'
            preferred_decision:
              type: object
              additionalProperties:
                type: string
              example:
                pay_up_to: 'Pay up to X hours (specify max time)'
                increment_up_to: 'Increment balance up to X hours (specify max time)'
            rest_policy:
              type: object
              additionalProperties:
                type: string
              example:
                add_to_balance: 'Add to balance'
                drop: 'Drop (ignore remaining hours)'
        limits:
          type: object
          description: 'Accepted range for the cap, in both units.'
          required:
            - min_seconds
            - max_seconds
            - min_hours
            - max_hours
          properties:
            min_seconds:
              type: integer
              format: int32
              example: 3600
            max_seconds:
              type: integer
              format: int32
              example: 115200
            min_hours:
              type: number
              format: float
              example: 1
            max_hours:
              type: number
              format: float
              example: 32
        defaults:
          type: object
          description: 'The values the form should start from when `configured` is false.'
          properties:
            auto_decision_policy:
              type: string
              example: skip_if_manual_decision
            preferred_decision:
              type: string
              example: pay_up_to
            rest_policy:
              type: string
              example: add_to_balance
            max_seconds:
              type: integer
              format: int32
              example: 3600
            max_hours:
              type: number
              format: float
              example: 1
            is_active:
              type: boolean
              example: true
    TempusCompiledUserWorkshift:
      type: object
      description: |
        A single compiled (precomputed) workshift entry for one Tempus employee on one
        calendar day, as serialized by the V1 `CompiledUserWorkshiftResource`. Each
        record summarizes the worked time the Tempus engine has rolled up for that day,
        attributing it to the employee's effective work shift and the ISO-style work
        week it falls into.

        This object documents the exact keys returned by the resource, not the raw
        database column names. Several keys are intentionally renamed for the public
        API: `mxvp_user_id` is the owning Pbx (tenant) identifier, `ext_id` is the
        Tempus employee identifier, and `user_workshift_id` is the linked employee
        work-shift identifier. The `date` value is normalized to a calendar date
        (YYYY-MM-DD), while `create_time` is the record's creation timestamp formatted
        as `YYYY-MM-DD HH:MM:SS`.

        Records are read-only: they are produced by the Tempus compilation process and
        exposed through the list endpoint, which supports `from`/`to` date filtering
        and sorting by `date`.
      required:
        - id
        - mxvp_user_id
        - ext_id
        - user_workshift_id
        - date
        - workshift_week
        - worktime
        - create_time
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the compiled workshift record.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this record (the raw `pbx_id`
            column). Named `mxvp_user_id` in the public API for historical reasons.
          example: 550e8400-e29b-41d4-a716-446655440001
        ext_id:
          type: string
          format: uuid
          description: |
            Identifier of the Tempus employee this compiled workshift belongs to (the
            raw `employee_id` column).
          example: 550e8400-e29b-41d4-a716-446655440002
        user_workshift_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the employee work shift this entry was compiled against (the
            raw `employee_work_shift_id` column). Null when no specific work shift was
            associated with the day.
          example: 550e8400-e29b-41d4-a716-446655440003
        date:
          type:
            - string
            - 'null'
          format: date
          description: |
            Calendar day this entry summarizes, normalized to YYYY-MM-DD. Null only if
            no date is set on the underlying record.
          example: '2024-03-01'
        workshift_week:
          type: integer
          format: int32
          description: |
            Week number the day falls into within the work-shift cycle, used to group
            daily entries into weekly totals.
          example: 9
        worktime:
          type: integer
          format: int32
          description: |
            Total compiled worked time for the day, expressed in seconds.
          example: 28800
        create_time:
          type:
            - string
            - 'null'
          description: |
            Timestamp when the record was created, formatted as `YYYY-MM-DD HH:MM:SS`
            (not ISO 8601). Null when the underlying creation timestamp is not set.
          example: '2024-03-01 08:29:07'
          readOnly: true
    TempusScheduleSummary:
      type: object
      description: |
        Tempus schedule (planning grid) as serialized by the V1 `ScheduleResource`. A
        schedule defines the time-attendance planning view for a single Tempus
        department: which weekdays are shown, the visible time window each day, and the
        granularity of the time slots in the grid. It optionally pins a default status
        and sub-status applied to new entries.

        This object documents the exact keys returned by the resource, not the raw
        database columns. Several values are reshaped by the resource:
        `days_to_display` is a 7-character bitmask string derived from the stored
        `days_of_week` array, and `slot_duration` is an `HH:MM:SS` time string derived
        from the stored `slot_duration_minutes` integer.

        A schedule also defines WHO it is for, via `scope_type`: whole companies, one or
        more groups (departments), or a hand-picked list of employees. `groups` lists every
        group the schedule covers and `employees` everyone who may be booked into its slots;
        build an assignment picker from `employees`.

        The `group` object mirrors the schedule's anchor group and is only present when the
        `department` relation is loaded on the model; it is omitted otherwise. Both `group`
        and `group_id` are null when the scope resolves to no group at all, which happens
        for a company-scoped schedule whose people hold contracts carrying no department.
        The `mxvp_user_id` at the top level is the schedule's own tenant (Pbx) identifier and
        is always present.
      required:
        - id
        - mxvp_user_id
        - name
        - group_id
        - scope_type
        - groups
        - employees
        - days_to_display
        - slot_min_time
        - slot_max_time
        - slot_duration
        - status_id
        - sub_status_id
        - delete_date
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique schedule identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        mxvp_user_id:
          type: string
          format: uuid
          description: |
            Identifier of the Pbx (tenant) that owns this schedule. Read from the schedule
            itself, so it is always present, including for a schedule with no anchor group.
          example: 550e8400-e29b-41d4-a716-446655440001
        name:
          type: string
          description: 'Human-readable name of the schedule.'
          example: 'Customer Support'
        group_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the Tempus department (planning group) this schedule is anchored
            to. Mirrors the model's `department_id`.

            Null when the schedule's scope resolves to no group, which happens for a
            company-scoped schedule whose people hold contracts carrying no department. Such
            a schedule is valid and fully usable: its people come from the company. Treat
            this field as optional and use `groups` for the full list.
          example: 550e8400-e29b-41d4-a716-446655440002
        days_to_display:
          type: string
          description: |
            Seven-character bitmask string indicating which weekdays are shown in the
            planning grid, ordered Monday through Sunday. Each position is "1" when the
            day is visible and "0" when it is hidden (for example "1111100" shows
            Monday to Friday). Derived from the stored `days_of_week` array.
          example: '1111100'
        slot_min_time:
          type:
            - string
            - 'null'
          description: |
            Start of the visible time window for each day, as an `HH:MM` time string.
            Null when no start time is configured.
          example: '08:00'
        slot_max_time:
          type:
            - string
            - 'null'
          description: |
            End of the visible time window for each day, as an `HH:MM` time string.
            Null when no end time is configured.
          example: '18:00'
        slot_duration:
          type: string
          description: |
            Duration of a single time slot in the planning grid, as an `HH:MM:SS` time
            string. Derived from the stored `slot_duration_minutes` integer (for
            example 30 minutes becomes "00:30:00"); defaults to 30 minutes.
          example: '00:30:00'
        status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the default Tempus status applied to entries created in this
            schedule. Null when no default status is set.
          example: 550e8400-e29b-41d4-a716-446655440003
        sub_status_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the default Tempus sub-status applied to entries created in
            this schedule. Null when no default sub-status is set.
          example: 550e8400-e29b-41d4-a716-446655440004
        delete_date:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Soft-delete timestamp for the schedule, as a `YYYY-MM-DD HH:MM:SS` string.
            Null when the schedule is active (not soft-deleted).
          example: '2024-03-01 08:29:07'
          readOnly: true
        group:
          type:
            - object
            - 'null'
          description: |
            The schedule's anchor Tempus department, included only when the `department`
            relation is loaded on the model; the key is omitted entirely otherwise. Null when
            the scope resolves to no group (see `group_id`).
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the department.'
              example: 550e8400-e29b-41d4-a716-446655440002
            mxvp_user_id:
              type:
                - string
                - 'null'
              format: uuid
              description: |
                Identifier of the Pbx (tenant) that owns the department. Null when no
                tenant is associated.
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type: string
              description: 'Display name of the department.'
              example: 'Sales Team'
            delete_date:
              type:
                - string
                - 'null'
              format: date-time
              description: |
                Soft-delete timestamp for the department, as a
                `YYYY-MM-DD HH:MM:SS` string. Null when the department is active.
              example: '2024-03-01 08:29:07'
              readOnly: true
        scope_type:
          type: string
          enum:
            - company
            - department
            - employees
          description: |
            Who the schedule is for:

            - `company`: everyone contracted with the selected companies.
            - `department`: everyone contracted in the selected groups (the default, and what
              a schedule created without a `scope_type` gets).
            - `employees`: exactly the selected people, who may come from different groups and
              different companies.
          example: department
        groups:
          type: array
          description: |
            Every group (department) the schedule covers, resolved from its scope. One entry for a classic single-group schedule; empty when the scope resolves to no group. `filter[group_id]` on the list endpoint matches against this, not only against the anchor `group_id`.
          items:
            type: object
            required:
              - id
              - name
            properties:
              id:
                type: string
                format: uuid
                description: 'Unique identifier of the group.'
                example: 550e8400-e29b-41d4-a716-446655440002
              name:
                type:
                  - string
                  - 'null'
                description: 'Display name of the group.'
                example: 'Sales Team'
          example:
            -
              id: 550e8400-e29b-41d4-a716-446655440002
              name: 'Sales Team'
        employees:
          type: array
          description: |
            Everyone who may be booked into the schedule's slots, resolved from its scope. Build an assignment picker from this list; booking anybody outside it is refused with a 422. The group fields are those of the employee's most recent contract and are null when that contract carries no department.
          items:
            type: object
            required:
              - id
              - full_name
              - group_id
              - group_name
            properties:
              id:
                type: string
                format: uuid
                description: 'Unique identifier of the employee.'
                example: 550e8400-e29b-41d4-a716-446655440010
              full_name:
                type: string
                description: 'Display name of the employee.'
                example: 'Jane Smith'
              group_id:
                type:
                  - string
                  - 'null'
                format: uuid
                description: "Group on the employee's most recent contract, or null."
                example: 550e8400-e29b-41d4-a716-446655440002
              group_name:
                type:
                  - string
                  - 'null'
                description: 'Name of that group, or null.'
                example: 'Sales Team'
          example:
            -
              id: 550e8400-e29b-41d4-a716-446655440010
              full_name: 'Jane Smith'
              group_id: 550e8400-e29b-41d4-a716-446655440002
              group_name: 'Sales Team'
    TempusScheduleManagement:
      type: object
      description: |
        Tempus schedule template as serialized by the `ScheduleResource`. A schedule
        defines a recurring planning grid: which weekdays it covers, the daily working
        window (start and end time), and the granularity of each bookable slot. It
        optionally pins a default status and sub-status applied to generated entries, and
        can restrict the statuses selectable on the grid.

        A schedule also defines WHO it is for, via `scopeType`: whole companies, one or
        more departments, or a hand-picked list of employees. `scope` reports the raw
        selection (only the list matching `scopeType` is populated), while `departments`
        and `employees` report the resolved coverage. `employees` is the definitive list of
        people who may be booked into the schedule's slots, and is what an assignment
        picker should be built from.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The `department`, `status`, and `subStatus` fields are
        relationship objects that are only present when the corresponding relation is
        eager-loaded on the model; when not loaded they are omitted from the payload
        entirely. The `dayStartTime` and `dayEndTime` values are returned trimmed to
        `HH:MM` (seconds are dropped). Times are local wall-clock values with no
        timezone component.
      required:
        - id
        - name
        - scopeType
        - scope
        - departments
        - employees
        - daysOfWeek
        - dayStartTime
        - dayEndTime
        - slotDurationMinutes
        - statusFilters
        - isActive
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique schedule identifier.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        name:
          type: string
          description: 'Human-readable name of the schedule template.'
          example: 'Sales Team Weekly Plan'
        department:
          type:
            - object
            - 'null'
          description: |
            The schedule's anchor department. Only present when the `department` relation is
            eager-loaded; otherwise this key is omitted.

            Null when the scope resolves to no department at all, which happens for a
            company-scoped schedule whose people hold contracts carrying no department. Such
            a schedule is valid and fully usable: its people come from the company. Treat
            this field as optional. Use `departments` for the full list of departments the
            schedule covers.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the department.'
              example: 550e8400-e29b-41d4-a716-446655440001
            name:
              type: string
              description: 'Display name of the department.'
              example: 'Customer Support'
        scopeType:
          type: string
          enum:
            - company
            - department
            - employees
          description: |
            Who the schedule is for:

            - `company`: everyone contracted with the selected companies.
            - `department`: everyone contracted in the selected departments (the default,
              and what a schedule created without a `scope_type` gets).
            - `employees`: exactly the selected people, who may come from different
              departments and different companies.
          example: department
        scope:
          type: object
          description: |
            The raw selection the schedule was configured with. Only the list matching `scopeType` is populated; the other two are empty arrays. Use this to pre-populate an edit form so it round-trips.
          required:
            - companies
            - departments
            - employees
          properties:
            companies:
              type: array
              description: 'Selected companies. Populated only when `scopeType` is `company`.'
              items:
                type: object
                required:
                  - id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the company.'
                    example: 550e8400-e29b-41d4-a716-446655440020
                  name:
                    type: string
                    description: 'Display name of the company.'
                    example: 'Northwind Trading'
              example: {}
            departments:
              type: array
              description: 'Selected departments. Populated only when `scopeType` is `department`.'
              items:
                type: object
                required:
                  - id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the department.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    description: 'Display name of the department.'
                    example: 'Customer Support'
              example:
                -
                  id: 550e8400-e29b-41d4-a716-446655440001
                  name: 'Customer Support'
            employees:
              type: array
              description: 'Selected employees. Populated only when `scopeType` is `employees`.'
              items:
                type: object
                required:
                  - id
                  - fullName
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the employee.'
                    example: 550e8400-e29b-41d4-a716-446655440010
                  fullName:
                    type: string
                    description: 'Display name of the employee.'
                    example: 'Jane Smith'
              example: {}
        departments:
          type: array
          description: |
            Every department the schedule covers, resolved from the scope. For a company scope these are the companies' departments; for an employee scope the departments on the selected employees' contracts. An empty array when the scope resolves to no department.
          items:
            type: object
            required:
              - id
              - name
            properties:
              id:
                type: string
                format: uuid
                description: 'Unique identifier of the department.'
                example: 550e8400-e29b-41d4-a716-446655440001
              name:
                type:
                  - string
                  - 'null'
                description: 'Display name of the department.'
                example: 'Customer Support'
          example:
            -
              id: 550e8400-e29b-41d4-a716-446655440001
              name: 'Customer Support'
        employees:
          type: array
          description: |
            Everyone the schedule may assign, resolved from the scope. This is the pool the slot assignment pickers and auto-assign draw from; booking anybody outside it is refused with a 422. The same list is available on its own from `GET /{pbx_id}/schedule-management/{schedule}/employees`.
          items:
            type: object
            description: |
              One assignable person of a schedule: an employee the schedule's scope covers and
              who may therefore be booked into its slots.

              Only employees holding a contract that is active today are listed — someone who has
              left, and someone whose contract has not started yet, is left out whatever the scope
              type, including a hand-picked `employees` selection. The schedule's `scope` still
              echoes the raw selection, so an edit form can round-trip what was picked.

              The department is the one on the employee's most recent contract, supplied so a
              picker can group or label its options when the schedule spans more than one
              department. Both department fields are null for an employee whose contract carries
              no department, which is normal for a company-scoped schedule.
            required:
              - id
              - fullName
              - departmentId
              - departmentName
            properties:
              id:
                type: string
                format: uuid
                description: 'Unique identifier of the employee.'
                example: 550e8400-e29b-41d4-a716-446655440010
              fullName:
                type: string
                description: |
                  Display name of the employee, ordered according to the tenant's first-name or last-name-first preference.
                example: 'Jane Smith'
              departmentId:
                type:
                  - string
                  - 'null'
                format: uuid
                description: |
                  Identifier of the department on the employee's most recent contract. Null when that contract carries no department.
                example: 550e8400-e29b-41d4-a716-446655440002
              departmentName:
                type:
                  - string
                  - 'null'
                description: |
                  Display name of the department on the employee's most recent contract. Null when that contract carries no department.
                example: 'Customer Support'
        daysOfWeek:
          type: array
          description: |
            Weekdays covered by this schedule, stored as ISO 8601 weekday numbers
            (1 = Monday through 7 = Sunday). Returned as an empty array when no days
            are configured.
          items:
            type: integer
            format: int32
            enum:
              - 1
              - 2
              - 3
              - 4
              - 5
              - 6
              - 7
            description: 'ISO 8601 weekday number (1 = Monday, 7 = Sunday).'
            example: 1
          example:
            - 1
            - 2
            - 3
            - 4
            - 5
        dayStartTime:
          type:
            - string
            - 'null'
          description: |
            Start of the daily working window in `HH:MM` 24-hour format (local
            wall-clock, no timezone). Null when no start time is configured.
          example: '09:00'
        dayEndTime:
          type:
            - string
            - 'null'
          description: |
            End of the daily working window in `HH:MM` 24-hour format (local
            wall-clock, no timezone). Null when no end time is configured.
          example: '17:30'
        slotDurationMinutes:
          type: integer
          format: int32
          description: |
            Length in minutes of each bookable slot within the daily window. Defaults
            to the configured Tempus slot duration (typically 30) when not set.
          example: 30
        status:
          type:
            - object
            - 'null'
          description: |
            Default status assigned to entries generated from this schedule. Only
            present when the `status` relation is eager-loaded; null when loaded but
            no default status is set, and omitted entirely when the relation is not
            loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the status.'
              example: 550e8400-e29b-41d4-a716-446655440002
            name:
              type: string
              description: 'Display name of the status.'
              example: Available
        subStatus:
          type:
            - object
            - 'null'
          description: |
            Default sub-status assigned to entries generated from this schedule. Only
            present when the `subStatus` relation is eager-loaded; null when loaded
            but no default sub-status is set, and omitted entirely when the relation
            is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the sub-status.'
              example: 550e8400-e29b-41d4-a716-446655440003
            name:
              type: string
              description: 'Display name of the sub-status.'
              example: 'On Break'
        statusFilters:
          type: array
          description: |
            Identifiers of the statuses that are selectable on this schedule's grid.
            Used to restrict which statuses planners may apply. Returned as an empty
            array when no filter is configured (all statuses allowed).
          items:
            type: string
            format: uuid
            description: 'Identifier of an allowed status.'
            example: 550e8400-e29b-41d4-a716-446655440002
          example:
            - 550e8400-e29b-41d4-a716-446655440002
            - 550e8400-e29b-41d4-a716-446655440003
        isActive:
          type: boolean
          description: |
            Whether the schedule is active. Inactive schedules are retained but not
            used to generate new planning entries.
          example: true
        createdAt:
          type:
            - string
            - 'null'
          format: date-time
          description: 'ISO 8601 timestamp when the schedule was created.'
          example: '2024-03-01T08:29:07+00:00'
          readOnly: true
        updatedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: 'ISO 8601 timestamp when the schedule was last updated.'
          example: '2024-03-01T08:29:07+00:00'
          readOnly: true
    TempusScheduleCalendar:
      type: object
      description: |
        Weekly calendar view of a Tempus schedule, returned by the
        `GET /{pbx_id}/schedules/{schedule}/calendar` endpoint. The payload expands the
        schedule's recurring slots and their booked entries across a single week,
        producing a ready-to-render grid for the planning UI.

        This object documents the exact keys returned by the calendar builder, not the
        raw database columns. The week always begins on a Monday: when no `week_start`
        query parameter is supplied it defaults to the Monday of the current week. The
        `days` array contains one entry per active weekday of the schedule (driven by
        the schedule's `days_of_week`), and each day carries the slots that recur on
        that date together with any entry booked into them.

        Note that the keys here use camelCase (for example `weekStart`, `dayLabel`,
        `columnIndex`), unlike the snake_case keys of the schedule object nested under
        `schedule`. All times are local wall-clock values formatted as `HH:MM` with no
        timezone component, interpreted in the application timezone.
      required:
        - schedule
        - weekStart
        - weekEnd
        - days
      properties:
        schedule:
          type: object
          description: |
            The schedule this calendar belongs to, serialized as a `ScheduleResource`
            with its `department`, `status`, and `subStatus` relations eager-loaded.
            See the TempusScheduleManagement schema for full field documentation.
        weekStart:
          type: string
          format: date
          description: |
            First day of the rendered week (always a Monday), as an ISO `YYYY-MM-DD`
            date. Matches the supplied `week_start` parameter when provided, otherwise
            the Monday of the current week.
          example: '2024-03-04'
        weekEnd:
          type: string
          format: date
          description: |
            Last day of the rendered week as an ISO `YYYY-MM-DD` date. Derived from the
            highest active weekday in the schedule's `days_of_week`, so it is not
            necessarily the following Sunday.
          example: '2024-03-08'
        days:
          type: array
          description: |
            One element per active weekday of the schedule within this week, ordered by
            weekday. Days on which the schedule is not active are omitted entirely.
          items:
            type: object
            required:
              - date
              - dayLabel
              - isToday
              - slots
            properties:
              date:
                type: string
                format: date
                description: 'Calendar date of this day as an ISO `YYYY-MM-DD` value.'
                example: '2024-03-04'
              dayLabel:
                type: string
                description: |
                  Human-readable label for the day, formatted as a localized short
                  weekday name followed by the date (`ddd DD.MM.YYYY`).
                example: 'Mon 04.03.2024'
              isToday:
                type: boolean
                description: 'Whether this day is the current date in the application timezone.'
                example: false
              slots:
                type: array
                description: |
                  Slot occurrences that recur on this day, sorted by column index then
                  start time. A slot with no bookings appears once with a null `entry`;
                  a slot with multiple bookings appears once per booked entry.
                items:
                  type: object
                  required:
                    - slotId
                    - renderKey
                    - columnIndex
                    - startTime
                    - endTime
                    - recurrenceType
                    - recurrenceDays
                    - recurrenceStartDate
                    - recurrenceEndDate
                    - entry
                  properties:
                    slotId:
                      type: string
                      format: uuid
                      description: 'Identifier of the schedule slot this cell represents.'
                      example: 550e8400-e29b-41d4-a716-446655440000
                    renderKey:
                      type: string
                      description: |
                        Stable key for client-side rendering and reconciliation. For an
                        unbooked slot it is `{slotId}:empty:{date}`; for a booked slot it
                        is `{slotId}:{entryId}`.
                      example: '550e8400-e29b-41d4-a716-446655440000:550e8400-e29b-41d4-a716-446655440010'
                    columnIndex:
                      type: integer
                      format: int32
                      description: |
                        Zero-based column the slot occupies in the grid, used to lay out
                        overlapping slots side by side.
                      example: 0
                    startTime:
                      type: string
                      description: |
                        Slot start time as `HH:MM`. For an exception entry (a moved
                        booking) this reflects the entry's actual start time rather than
                        the slot's nominal start.
                      example: '09:00'
                    endTime:
                      type: string
                      description: |
                        Slot end time as `HH:MM`. For an exception entry this reflects
                        the entry's actual end time rather than the slot's nominal end.
                      example: '17:00'
                    recurrenceType:
                      type: string
                      enum:
                        - none
                        - daily
                        - weekly
                        - custom
                      description: 'Recurrence rule governing on which dates the slot appears.'
                      example: weekly
                    recurrenceDays:
                      type:
                        - array
                        - 'null'
                      description: |
                        Weekday numbers the slot recurs on for `weekly` and `custom`
                        recurrence. Null for `none` and `daily` recurrence.
                      items:
                        type: integer
                        format: int32
                        description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                        example: 1
                      example:
                        - 1
                        - 2
                        - 3
                        - 4
                        - 5
                    recurrenceStartDate:
                      type:
                        - string
                        - 'null'
                      format: date
                      description: |
                        First date from which the slot's recurrence applies, as an ISO
                        `YYYY-MM-DD` value, or null when unbounded.
                      example: '2024-01-01'
                    recurrenceEndDate:
                      type:
                        - string
                        - 'null'
                      format: date
                      description: |
                        Last date on which the slot's recurrence applies, as an ISO
                        `YYYY-MM-DD` value, or null when the recurrence has no end date.
                      example: '2024-12-31'
                    entry:
                      type:
                        - object
                        - 'null'
                      description: |
                        The booking occupying this slot on this date, or null when the
                        slot is unbooked for the day.
                      required:
                        - entryId
                        - employeeId
                        - userName
                        - color
                        - comment
                        - isException
                      properties:
                        entryId:
                          type: string
                          format: uuid
                          description: 'Identifier of the schedule entry (booking).'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        employeeId:
                          type: string
                          format: uuid
                          description: 'Identifier of the Tempus employee assigned to the slot.'
                          example: 550e8400-e29b-41d4-a716-446655440020
                        userName:
                          type:
                            - string
                            - 'null'
                          description: |
                            Full name of the assigned employee for display, or null when
                            the employee record cannot be resolved.
                          example: 'Jane Smith'
                        color:
                          type: string
                          description: |
                            Hex color assigned to this employee within the schedule, used
                            to tint their entries on the grid. Assigned automatically on
                            first use if not already set.
                          example: '#4F46E5'
                        comment:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-form note attached to the booking.'
                          example: 'Covering the morning desk'
                        isException:
                          type: boolean
                          description: |
                            Whether this entry deviates from the slot's recurring times
                            (for example after being moved). When true the cell's
                            `startTime` and `endTime` reflect the entry's own times.
                          example: false
    TempusScheduleEmployee:
      type: object
      description: |
        One assignable person of a schedule: an employee the schedule's scope covers and
        who may therefore be booked into its slots.

        Only employees holding a contract that is active today are listed — someone who has
        left, and someone whose contract has not started yet, is left out whatever the scope
        type, including a hand-picked `employees` selection. The schedule's `scope` still
        echoes the raw selection, so an edit form can round-trip what was picked.

        The department is the one on the employee's most recent contract, supplied so a
        picker can group or label its options when the schedule spans more than one
        department. Both department fields are null for an employee whose contract carries
        no department, which is normal for a company-scoped schedule.
      required:
        - id
        - fullName
        - departmentId
        - departmentName
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the employee.'
          example: 550e8400-e29b-41d4-a716-446655440010
        fullName:
          type: string
          description: |
            Display name of the employee, ordered according to the tenant's first-name or last-name-first preference.
          example: 'Jane Smith'
        departmentId:
          type:
            - string
            - 'null'
          format: uuid
          description: |
            Identifier of the department on the employee's most recent contract. Null when that contract carries no department.
          example: 550e8400-e29b-41d4-a716-446655440002
        departmentName:
          type:
            - string
            - 'null'
          description: |
            Display name of the department on the employee's most recent contract. Null when that contract carries no department.
          example: 'Customer Support'
    TempusScheduleEntry:
      type: object
      description: |
        A single Tempus schedule entry: one assignment of an employee to a time slot
        within a published schedule, as serialized by `EntryResource`. An entry pins a
        concrete start and end datetime, an optional comment, and a display colour
        resolved from the employee's per-schedule colour mapping.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The `employee` and `assignedBy` objects are relationship
        summaries that are only present when their relation is eager-loaded on the
        model. When the relation is loaded but the related record is missing they are
        returned as null, and when the relation is not loaded the key is omitted from
        the payload entirely; integrators should treat both as "no data available".

        The `color` value is a computed accessor (`color_hex`) looked up from the
        employee's colour assignment for this schedule, so it can be null when no
        colour has been configured.
      required:
        - id
        - slotId
        - scheduleId
        - color
        - startDatetime
        - endDatetime
        - comment
        - isException
        - assignedAt
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the schedule entry.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        slotId:
          type: string
          format: uuid
          description: |
            Identifier of the schedule slot (the recurring template position) this
            entry was generated from or assigned to.
          example: 550e8400-e29b-41d4-a716-446655440001
        scheduleId:
          type: string
          format: uuid
          description: 'Identifier of the parent schedule this entry belongs to.'
          example: 550e8400-e29b-41d4-a716-446655440002
        employee:
          type:
            - object
            - 'null'
          description: |
            Summary of the employee assigned to this entry. Only present when the
            `employee` relation is loaded; returned as null when the relation is
            loaded but the employee record cannot be resolved, and omitted entirely
            when the relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Identifier of the assigned employee.'
              example: 550e8400-e29b-41d4-a716-446655440003
            fullName:
              type: string
              description: 'Display name of the assigned employee.'
              example: 'Jane Smith'
        color:
          type:
            - string
            - 'null'
          description: |
            Hex colour code used to display this entry, resolved from the employee's
            colour assignment for this schedule. Null when no colour has been
            configured for the employee in this schedule. Read-only computed value.
          readOnly: true
          example: '#3B82F6'
        startDatetime:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Start of the entry as an ISO 8601 datetime with timezone offset. Null when
            the start has not been set.
          example: '2024-03-01T08:00:00+00:00'
        endDatetime:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            End of the entry as an ISO 8601 datetime with timezone offset. Null when
            the end has not been set.
          example: '2024-03-01T16:30:00+00:00'
        comment:
          type:
            - string
            - 'null'
          description: 'Optional free-form note attached to this entry.'
          example: 'Covering the morning reception shift'
        isException:
          type: boolean
          description: |
            Whether this entry is an exception (a manual override) rather than an
            entry generated from the recurring slot template.
          example: false
        assignedBy:
          type:
            - object
            - 'null'
          description: |
            Summary of the user who created this assignment. Only present when the
            `assignedBy` relation is loaded; returned as null when the relation is
            loaded but the user cannot be resolved, and omitted entirely when the
            relation is not loaded.
          properties:
            id:
              type: string
              format: uuid
              description: 'Identifier of the user who made the assignment.'
              example: 550e8400-e29b-41d4-a716-446655440004
            name:
              type: string
              description: 'Display name of the user who made the assignment.'
              example: 'Customer Support'
        assignedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            ISO 8601 timestamp with timezone offset for when the entry was assigned.
            Null when no assignment time has been recorded.
          example: '2024-03-01T07:45:12+00:00'
    TempusScheduleSlot:
      type: object
      description: |
        A single recurring time slot belonging to a Tempus schedule, as serialized by
        the `SlotResource`. A slot defines a daily start and end time together with a
        recurrence rule (which days it repeats on and over what date range) and a
        column position used to lay out overlapping slots side by side in the schedule
        grid. Schedule entries (the concrete occurrences worked against the slot) are
        attached through the related `TempusScheduleEntry` records and are not embedded
        in this object.

        This object documents the exact keys returned by the resource, not the raw
        database columns. The `createdBy` field is only present when the `createdBy`
        relation has been eager-loaded on the model; when it is loaded it is a compact
        object (or null), and when it is not loaded the key is omitted entirely.

        Times are returned trimmed to `HH:MM` (seconds removed). The recurrence date
        fields are returned as plain `YYYY-MM-DD` calendar dates without a time
        component.
      required:
        - id
        - scheduleId
        - columnIndex
        - startTime
        - endTime
        - recurrenceType
        - recurrenceDays
        - recurrenceStartDate
        - recurrenceEndDate
        - recurrenceCount
        - isActive
      properties:
        id:
          type: string
          format: uuid
          description: 'Unique identifier of the schedule slot.'
          example: 550e8400-e29b-41d4-a716-446655440000
          readOnly: true
        scheduleId:
          type: string
          format: uuid
          description: 'Identifier of the parent Tempus schedule this slot belongs to.'
          example: 550e8400-e29b-41d4-a716-446655440001
        columnIndex:
          type: integer
          format: int32
          description: |
            Zero-based column position used to render the slot in the schedule grid.
            Overlapping active slots receive distinct column indices so they can be
            displayed side by side; the lowest free index is assigned automatically.
          example: 0
        startTime:
          type: string
          description: |
            Daily start time of the slot in 24-hour `HH:MM` form. Seconds are trimmed
            from the stored value before serialization.
          example: '09:00'
        endTime:
          type: string
          description: |
            Daily end time of the slot in 24-hour `HH:MM` form. Seconds are trimmed
            from the stored value before serialization.
          example: '17:30'
        recurrenceType:
          type: string
          enum:
            - daily
            - weekly
            - monthly
            - none
          description: |
            Recurrence frequency rule that governs how the slot repeats. Determines
            how `recurrenceDays`, `recurrenceEndDate` and `recurrenceCount` are
            interpreted.
          example: weekly
        recurrenceDays:
          type:
            - array
            - 'null'
          description: |
            Days the slot recurs on, used together with `recurrenceType`. For a weekly
            recurrence these are ISO weekday numbers (1 = Monday through 7 = Sunday);
            for a monthly recurrence they are days of the month. Null when no specific
            days apply to the recurrence rule.
          items:
            type: integer
            format: int32
            example: 1
          example:
            - 1
            - 2
            - 3
            - 4
            - 5
        recurrenceStartDate:
          type:
            - string
            - 'null'
          format: date
          description: |
            First calendar date on which the slot recurrence becomes active, in
            `YYYY-MM-DD` form. Null when no start date is set.
          example: '2024-03-01'
        recurrenceEndDate:
          type:
            - string
            - 'null'
          format: date
          description: |
            Last calendar date on which the slot recurrence remains active, in
            `YYYY-MM-DD` form. Null for an open-ended recurrence or when the
            recurrence is instead bounded by `recurrenceCount`.
          example: '2024-12-31'
        recurrenceCount:
          type:
            - integer
            - 'null'
          format: int32
          description: |
            Number of occurrences after which the recurrence ends. Null when the
            recurrence is open-ended or bounded by `recurrenceEndDate` instead of a
            fixed count.
          example: 12
        isActive:
          type: boolean
          description: |
            Whether the slot is currently active. Inactive slots are retained but are
            excluded from grid layout and column-index assignment.
          example: true
        createdBy:
          type:
            - object
            - 'null'
          description: |
            Compact reference to the user who created the slot. Only present when the
            `createdBy` relation is eager-loaded; the key is omitted otherwise. Null
            when the relation is loaded but no creating user is associated.
          readOnly: true
          properties:
            id:
              type: string
              format: uuid
              description: 'Unique identifier of the user who created the slot.'
              example: 550e8400-e29b-41d4-a716-446655440002
            name:
              type: string
              description: 'Display name of the user who created the slot.'
              example: 'Customer Support'
security:
  -
    bearerAuth: {}
tags:
  -
    name: Auth
    x-displayName: Authentication
    description: |
      Every endpoint uses **bearer token** authentication: send your token in the `Authorization` header on every request:

      ```
      Authorization: Bearer <token>
      ```

      There are two kinds of token:

      - **User token** - obtained by calling `POST /login` with a user's credentials. It inherits that user's permissions and is scoped to their PBX(es). There is no separate "global" token; broader access comes from logging in as a user with broader role assignments (e.g. a super-admin).
      - **PBX API key** - created by the customer on the Cockpit **Integrations** page (an "API key" integration). It is owned by the PBX and limited to the scopes selected when the key was created.

      Both kinds authenticate against the same endpoints. **Which fields a response contains can depend on the token type:** a few *per-user* fields are returned for user tokens and omitted for PBX API keys (see **Principal-conditional fields** above, and the `PRINCIPAL-CONDITIONAL` note on the affected fields).

      Per-operation auth requirements are listed under each endpoint's **Security** section.
  -
    name: AiConfiguration
    x-displayName: 'AI configuration'
    description: 'Read-only aggregated AI setup for a PBX (global prompt, labels, keyword tree, per-extension and per-group prompts, AI profile and feature flags). Read with a PBX API key carrying the `ai-configuration` scope.'
  -
    name: CallerIdentities
    x-displayName: 'Caller Identities'
    description: 'Caller identities represent the outbound phone numbers (and optional suffixes) available to the authenticated user when placing calls. Each identity is linked to a phone number and a target entity (User, PBX, Group, or SIP device).'
  -
    name: Calls
    x-displayName: Calls
    description: 'Endpoints for initiating and managing outbound calls.'
  -
    name: CallFlows
    x-displayName: 'Call Flows'
    description: 'Define how inbound calls are routed through your PBX. A call flow chains ordered steps (transfer, IVR, voicemail, queue, schedule) that the system evaluates per call.'
  -
    name: CallFlowSteps
    x-displayName: 'Call Flow Steps'
    description: 'Individual steps belonging to a call flow. Each step has a type and a target (extension, queue, sound file, IVR, etc.) and is executed in order.'
  -
    name: Contacts
    x-displayName: Contacts
    description: 'Shared address book entries available across the PBX.'
  -
    name: ContactImports
    x-displayName: 'Contact Imports'
    description: 'Import personal contacts from a CSV or Excel file via a guided upload, map, and confirm flow. Each import and every contact it creates is private to the authenticated user.'
  -
    name: Extensions
    x-displayName: Extensions
    description: 'Internal dial numbers assigned to users, devices, queues, and other PBX entities.'
  -
    name: Groups
    x-displayName: Groups
    description: 'Ring groups that dial multiple destinations simultaneously or in sequence.'
  -
    name: IVR
    x-displayName: IVR
    description: 'Interactive Voice Response menus that play a prompt and route the caller based on the key they press.'
  -
    name: 'IVR Steps'
    x-displayName: 'IVR Steps'
    description: 'Individual menu options inside an IVR. Each step maps a digit (or timeout) to a destination.'
  -
    name: Languages
    x-displayName: Languages
    description: 'Languages available for sound files, voice prompts, and user preferences.'
  -
    name: Locations
    x-displayName: Locations
    description: 'Physical offices or sites associated with the PBX, used for emergency call routing and reporting.'
  -
    name: Numbers
    x-displayName: 'Phone Number Orders'
    description: |
      Customer-facing endpoints for the Nexus number-order proxy. Use these to
      check whether a phone number can be provisioned at a given address, place
      an order (with KYC documents attached), retrieve an order's status, edit
      and retry an order that failed submission, list the phone numbers already
      owned by the PBX, and attach a call flow to a specific number.

      Authentication is the PBX API key (one token per PBX); every response is
      scoped to that PBX.
  -
    name: 'Push configuration'
    x-displayName: 'Push configuration'
    description: |
      Push the PBX configuration so pending changes take effect - the programmatic equivalent of the "Push configuration"
      button in Cockpit. PBX API key auth; rate limited to 1 request/minute per PBX.
  -
    name: OdooInstaller
    x-displayName: 'Odoo Installer'
    description: |
      Endpoints consumed by the Voxbi Installer module running inside a customer's Odoo.
      Register the Odoo integration, poll the install status, read it back, and update or
      re-run it. Authenticated with a customer API key carrying the `odoo-installer`
      ability; the PBX is resolved from the key.
  -
    name: Pbxes
    x-displayName: Pbxes
    description: 'The tenant container. Every other resource is scoped to a PBX.'
  -
    name: PhoneNumbers
    x-displayName: 'Phone Numbers'
    description: 'External DIDs owned by the PBX. Numbers are linked to call flows, users, or queues for inbound routing.'
  -
    name: Queues
    x-displayName: Queues
    description: 'Call queues that hold callers until an agent is available, with configurable strategies and music on hold.'
  -
    name: SipCarriers
    x-displayName: 'SIP Carriers'
    description: 'Upstream SIP trunks used for outbound calls and number termination.'
  -
    name: SipDevices
    x-displayName: 'SIP Devices'
    description: 'Physical or soft SIP endpoints (deskphones, softphones, ATAs) registered against the PBX.'
  -
    name: SoundFiles
    x-displayName: 'Sound Files'
    description: 'Audio files used for greetings, prompts, music on hold, and voicemail.'
  -
    name: Statuses
    x-displayName: Statuses
    description: 'Top-level presence values (e.g. Available, Busy, Away) that users can broadcast.'
  -
    name: Substatuses
    x-displayName: Substatuses
    description: 'Refinements under a parent status (e.g. Away > Lunch, Away > Meeting).'
  -
    name: Tags
    x-displayName: Tags
    description: 'Free-form labels attached to users, devices, or numbers for filtering and reporting.'
  -
    name: Schedules
    x-displayName: Schedules
    description: 'Time-of-day rule sets used by call flows to route differently inside vs outside business hours.'
  -
    name: Twinning
    x-displayName: Twinning
    description: "Ring an external number in parallel with the user's extension."
  -
    name: DND
    x-displayName: 'Do Not Disturb'
    description: 'Manage Do Not Disturb rules for users and extensions.'
  -
    name: Images
    x-displayName: Images
    description: 'Retrieve images (avatars, logos) associated with models.'
  -
    name: UserGroups
    x-displayName: 'User Groups'
    description: 'Manage user groups for organizing users within a PBX.'
  -
    name: Pools
    x-displayName: Pools
    description: 'Extension pools and their user assignments.'
  -
    name: VoxbiGroupTabs
    x-displayName: 'Voxbi Group Tabs'
    description: 'Custom tab configurations for Voxbi group views.'
  -
    name: Users
    x-displayName: Users
    description: 'PBX users. Each user owns an extension, devices, presence status, and forwarding rules.'
  -
    name: Webhooks
    x-displayName: Webhooks
    description: 'Inbound webhooks from third-party services (e.g. Famulor post-call events).'
  -
    name: OdooCatalogue
    x-displayName: 'Odoo Catalogue (public)'
    description: |
      The ONE Odoo endpoint outside the cockpit partner interface: a distributor reads
      their own Odoo products, and optionally their subscriptions, from their own system.

      Authenticated with a Partner-owned bearer token carrying the `odoo-catalogue`
      ability. "Public" means "not the cockpit UI session", not unauthenticated. The
      partner in the path is readability only: the token decides which Odoo is read and a
      mismatch answers 404.

      Subscriptions additionally require the `odoo-subscriptions` ability, because that
      block is a commercial ledger rather than a price list. When it is withheld the three
      subscription keys still appear, carrying the reason.

      Separate from the `OdooCrm` tag on purpose: everything there is session-scoped and
      internal, and this is the surface a third party writes code against.
  -
    name: CDRs
    x-displayName: 'CDR Utility'
    description: |
      ### CDR Utility Proxy

      Forwards authenticated requests to the internal CDRs API. Rate-limited to 120 requests/minute per user.

      Base URL: `/api/v1/cdrs-utility/`
  -
    name: TempusAbsences
    x-displayName: Absences
    description: 'Employee absence requests, absence records, and validator decisions on them.'
  -
    name: TempusHomeOffice
    x-displayName: 'Home office'
    description: 'Home office requests, home office calendars, and validator decisions on them.'
  -
    name: TempusCorrections
    x-displayName: Corrections
    description: 'Time point correction requests and validator decisions on them.'
  -
    name: TempusOvertime
    x-displayName: Overtime
    description: 'Overtime calculation periods and per-employee overtime decisions.'
  -
    name: TempusWorkTimes
    x-displayName: 'Work times'
    description: 'Weekly and required work times and compiled workshifts.'
  -
    name: TempusSchedules
    x-displayName: Schedules
    description: 'Managed work schedules, slots, and entry assignments.'
  -
    name: TempusCalendar
    x-displayName: Calendar
    description: 'Company and per-employee absence, home office, and personal calendars.'
  -
    name: TempusProfile
    x-displayName: Profile
    description: 'Employee profile, holidays reports, associated companies, and next availability.'
  -
    name: TempusReports
    x-displayName: Reports
    description: 'Worked-time reports and yearly summary totals per employee.'
  -
    name: TempusEmployees
    x-displayName: Employees
    description: 'Tempus employees, departments, and their time points.'
  -
    name: TempusValidators
    x-displayName: Validators
    description: 'Validator scope and validator-facing pending requests and corrections.'
  -
    name: TempusInternal
    x-displayName: 'Tempus terminals and recurring transactions'
    description: 'Tempus endpoints for badge readers and NFC terminals (authenticated with a PBX API-key token carrying the `terminals` ability) and for managing recurring transactions (PBX API key).'
  -
    name: v2
    x-displayName: 'API v2'
    description: |
      ### API v2 Endpoints

      Second-generation endpoints with improved response structures.

      Base URL: `/api/v2/`
  -
    name: aiConfigurationModel
    x-displayName: 'AI configuration'
    description: '<SchemaDefinition schemaRef="#/components/schemas/AiConfiguration" />'
  -
    name: callerIdentityModel
    x-displayName: 'Caller Identity'
    description: '<SchemaDefinition schemaRef="#/components/schemas/CallerIdentity" />'
  -
    name: callFlowModel
    x-displayName: 'Call Flow'
    description: '<SchemaDefinition schemaRef="#/components/schemas/CallFlow" />'
  -
    name: callFlowStepModel
    x-displayName: 'Call Flow Step'
    description: '<SchemaDefinition schemaRef="#/components/schemas/CallFlowStep" />'
  -
    name: contactModel
    x-displayName: Contact
    description: '<SchemaDefinition schemaRef="#/components/schemas/Contact" />'
  -
    name: contactImportModel
    x-displayName: 'Contact Import'
    description: '<SchemaDefinition schemaRef="#/components/schemas/ContactImport" />'
  -
    name: extensionModel
    x-displayName: Extension
    description: '<SchemaDefinition schemaRef="#/components/schemas/Extension" />'
  -
    name: groupModel
    x-displayName: Group
    description: '<SchemaDefinition schemaRef="#/components/schemas/Group" />'
  -
    name: ivrModel
    x-displayName: IVR
    description: '<SchemaDefinition schemaRef="#/components/schemas/IVR" />'
  -
    name: ivrStepModel
    x-displayName: 'IVR Step'
    description: '<SchemaDefinition schemaRef="#/components/schemas/IVRStep" />'
  -
    name: languageModel
    x-displayName: Language
    description: '<SchemaDefinition schemaRef="#/components/schemas/Language" />'
  -
    name: locationModel
    x-displayName: Location
    description: '<SchemaDefinition schemaRef="#/components/schemas/Location" />'
  -
    name: pbxModel
    x-displayName: Pbx
    description: '<SchemaDefinition schemaRef="#/components/schemas/Pbx" />'
  -
    name: phoneNumberModel
    x-displayName: 'Phone Number'
    description: '<SchemaDefinition schemaRef="#/components/schemas/PhoneNumber" />'
  -
    name: queueModel
    x-displayName: Queue
    description: '<SchemaDefinition schemaRef="#/components/schemas/Queue" />'
  -
    name: sipCarrierModel
    x-displayName: 'Sip Carrier'
    description: '<SchemaDefinition schemaRef="#/components/schemas/SipCarrier" />'
  -
    name: sipDeviceModel
    x-displayName: 'Sip Device'
    description: '<SchemaDefinition schemaRef="#/components/schemas/SipDevice" />'
  -
    name: soundFileModel
    x-displayName: 'Sound File'
    description: '<SchemaDefinition schemaRef="#/components/schemas/SoundFile" />'
  -
    name: statusModel
    x-displayName: Status
    description: '<SchemaDefinition schemaRef="#/components/schemas/Status" />'
  -
    name: subStatusModel
    x-displayName: Substatus
    description: '<SchemaDefinition schemaRef="#/components/schemas/Substatus" />'
  -
    name: tagModel
    x-displayName: Tag
    description: '<SchemaDefinition schemaRef="#/components/schemas/Tag" />'
  -
    name: scheduleModel
    x-displayName: Schedule
    description: '<SchemaDefinition schemaRef="#/components/schemas/Schedule" />'
  -
    name: twinningModel
    x-displayName: Twinning
    description: '<SchemaDefinition schemaRef="#/components/schemas/Twinning" />'
  -
    name: userModel
    x-displayName: User
    description: '<SchemaDefinition schemaRef="#/components/schemas/User" />'
  -
    name: inCallStateModel
    x-displayName: InCallState
    description: '<SchemaDefinition schemaRef="#/components/schemas/InCallState" />'
  -
    name: Metadata
    x-displayName: Metadata
    description: '<SchemaDefinition schemaRef="#/components/schemas/Metadata" />'
  -
    name: Links
    x-displayName: Links
    description: '<SchemaDefinition schemaRef="#/components/schemas/Links" />'
x-tagGroups:
  -
    name: Telephony
    tags:
      - Auth
      - AiConfiguration
      - Calls
      - CallFlows
      - CallFlowSteps
      - IVR
      - 'IVR Steps'
      - Queues
      - Schedules
      - PhoneNumbers
      - CallerIdentities
      - SipCarriers
      - SipDevices
      - Extensions
      - Twinning
      - DND
      - Users
      - UserGroups
      - Groups
      - Pools
      - Tags
      - Statuses
      - Substatuses
      - VoxbiGroupTabs
      - Pbxes
      - Locations
      - Languages
      - SoundFiles
      - Contacts
      - ContactImports
      - Images
      - SmartIvr
      - Webhooks
      - UserProvisioning
      - DirectLogin
      - PbxServerApi
      - Roaming
      - sts
      - Numbers
      - 'Push configuration'
      - OdooInstaller
  -
    name: Tempus
    tags:
      - TempusAbsences
      - TempusHomeOffice
      - TempusCorrections
      - TempusOvertime
      - TempusWorkTimes
      - TempusSchedules
      - TempusCalendar
      - TempusProfile
      - TempusReports
      - TempusEmployees
      - TempusValidators
      - TempusInternal
  -
    name: Partner
    tags:
      - Partner
      - OdooCrm
      - OdooCatalogue
  -
    name: 'API v2'
    tags:
      - v2
  -
    name: CDRs
    tags:
      - CDRs
  -
    name: Models
    tags:
      - aiConfigurationModel
      - callerIdentityModel
      - callFlowModel
      - callFlowStepModel
      - contactModel
      - contactImportModel
      - extensionModel
      - groupModel
      - ivrModel
      - ivrStepModel
      - languageModel
      - locationModel
      - pbxModel
      - phoneNumberModel
      - queueModel
      - sipCarrierModel
      - sipDeviceModel
      - soundFileModel
      - statusModel
      - subStatusModel
      - tagModel
      - scheduleModel
      - twinningModel
      - userModel
      - inCallStateModel
      - Metadata
      - Links
paths:
  /login:
    post:
      security: {}
      tags:
        - Auth
      summary: 'Log in with email and password (public)'
      operationId: postAuthLogin
      description: 'Authenticates a user with email and password and returns a personal access token used as the Bearer credential on every subsequent request.'
      x-codeSamples:
        -
          lang: curl
          label: cURL
          source: |
            curl -X POST 'https://cockpit.voxbi.com/api/v1/login' \
              -H 'Accept: application/json' \
              -H 'Content-Type: application/json' \
              -d '{
                "email": "user@example.com",
                "password": "strongPassword"
              }'
        -
          lang: JavaScript
          label: 'JavaScript (fetch)'
          source: |
            const res = await fetch('https://cockpit.voxbi.com/api/v1/login', {
              method: 'POST',
              headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                email: 'user@example.com',
                password: 'strongPassword',
              }),
            });
            const { data } = await res.json();
            const token = data.token;
        -
          lang: PHP
          label: 'PHP (Guzzle)'
          source: |
            $client = new GuzzleHttp\Client();
            $response = $client->post('https://cockpit.voxbi.com/api/v1/login', [
                'headers' => ['Accept' => 'application/json'],
                'json' => [
                    'email' => 'user@example.com',
                    'password' => 'strongPassword',
                ],
            ]);
            $token = json_decode($response->getBody())->data->token;
        -
          lang: Python
          label: 'Python (requests)'
          source: |
            import requests

            res = requests.post(
                'https://cockpit.voxbi.com/api/v1/login',
                headers={'Accept': 'application/json'},
                json={'email': 'user@example.com', 'password': 'strongPassword'},
            )
            token = res.json()['data']['token']
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
            example:
              email: user@example.com
              password: strongPassword
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      token:
                        type: string
                        description: 'Personal access token to send in the Authorization header as a Bearer credential on subsequent requests.'
              example:
                message: 'User Logged In Successfully'
                data:
                  token: 2|BeLWgqvfWsJTftMZ8mp2LGKdTUUCYb1HpFQJciEjb96187d8
        401:
          description: 'Invalid email or password.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid email or password.'
        403:
          description: 'The user account is disabled.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'User is not active.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /me:
    get:
      tags:
        - Auth
      summary: 'Get the authenticated user (user)'
      operationId: getAuthMe
      description: "Returns the currently authenticated user's profile data including extensions, SIP devices, groups, twinnings, and integrations. Requires a user-owned bearer token."
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      pbx_id:
                        type: string
                      full_name_with_email:
                        type: string
                      first_name:
                        type: string
                      last_name:
                        type: string
                      email:
                        type: string
                        format: email
                      language:
                        type: string
                      access_token:
                        type:
                          - string
                          - 'null'
                      email_verified_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                      status:
                        type: string
                      allow_telephony:
                        type: boolean
                      allow_dnd:
                        type: boolean
                      allow_change_twinning_dest:
                        type: boolean
                      allow_call_forwarding:
                        type: boolean
                      allow_manage_global_contacts:
                        type: boolean
                      call_recordings_visibility:
                        type:
                          - string
                          - 'null'
                      extension_roaming:
                        type: boolean
                      call_information_visibility:
                        type:
                          - string
                          - 'null'
                      allow_status_changer:
                        type: boolean
                      allow_manage_voicemail_parameters:
                        type: boolean
                      show_in_address_book:
                        type: boolean
                      voicemail_type:
                        type:
                          - string
                          - 'null'
                      voicemail_destination:
                        type:
                          - string
                          - 'null'
                      concurrent_calls:
                        type:
                          - integer
                          - 'null'
                      vip:
                        type: boolean
                      sync_source:
                        type:
                          - string
                          - 'null'
                      allow_anonymous_calls:
                        type: boolean
                      identity_provider_uid:
                        type:
                          - string
                          - 'null'
                      is_shadow:
                        type: boolean
                      created_at:
                        type: string
                        format: date-time
                      updated_at:
                        type: string
                        format: date-time
                      webrtc_configuration:
                        type:
                          - object
                          - 'null'
                      extensions:
                        type: array
                        items:
                          type: object
                      sipDevices:
                        type: array
                        items:
                          type: object
                      groups:
                        type: array
                        items:
                          type: object
                      twinnings:
                        type: array
                        items:
                          type: object
                      caller_identities:
                        type: array
                        items:
                          type: object
                      integrations:
                        type: array
                        items:
                          type: object
                      pbx:
                        type: object
                      microsoft:
                        type: object
                        properties:
                          fetch_contacts:
                            type: boolean
                      odoo:
                        type: object
                        properties:
                          fetch_contacts:
                            type: boolean
                      employee_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      tempus:
                        type:
                          - string
                          - 'null'
              example:
                message: Success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id: pbx-123
                  full_name_with_email: 'John Doe (john.doe@example.com)'
                  first_name: John
                  last_name: Doe
                  email: john.doe@example.com
                  language: en
                  access_token: null
                  email_verified_at: '2023-01-01T00:00:00.000000Z'
                  status: active
                  allow_telephony: true
                  allow_dnd: true
                  allow_change_twinning_dest: false
                  allow_call_forwarding: true
                  allow_manage_global_contacts: false
                  call_recordings_visibility: null
                  extension_roaming: false
                  call_information_visibility: null
                  allow_status_changer: true
                  allow_manage_voicemail_parameters: false
                  show_in_address_book: true
                  voicemail_type: null
                  voicemail_destination: null
                  concurrent_calls: null
                  vip: false
                  sync_source: null
                  allow_anonymous_calls: false
                  identity_provider_uid: null
                  is_shadow: false
                  created_at: '2023-01-01T00:00:00.000000Z'
                  updated_at: '2023-10-12T12:25:52.000000Z'
                  webrtc_configuration: null
                  extensions: {}
                  sipDevices: {}
                  groups: {}
                  twinnings: {}
                  caller_identities: {}
                  integrations: {}
                  pbx: {}
                  microsoft:
                    fetch_contacts: false
                  odoo:
                    fetch_contacts: false
                  employee_id: null
                  tempus: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /user:
    get:
      tags:
        - Auth
      summary: 'Get the authenticated user record (user)'
      operationId: getAuthUserRecord
      description: |
        Returns the raw authenticated user model (the owner of the Sanctum token). This is a
        thin endpoint that serialises the user record directly; for the assembled profile with
        extensions, SIP devices, groups, twinnings and integrations use `GET /me` instead.
        Hidden attributes (password, tokens) are never serialised.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  pbx_id:
                    type: string
                    format: uuid
                  first_name:
                    type: string
                  last_name:
                    type: string
                  email:
                    type: string
                    format: email
                  status:
                    type: string
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                first_name: John
                last_name: Doe
                email: john.doe@example.com
                status: active
                created_at: '2026-01-01T00:00:00+00:00'
                updated_at: '2026-06-01T12:25:52+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  '/magic-login/{token}':
    get:
      tags:
        - Auth
      summary: 'Log in with a magic link token'
      operationId: getAuthMagicLogin
      description: 'Authenticates a user via a magic link token. Returns a redirect or JSON response on success.'
      security: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
        -
          name: token
          in: path
          required: true
          schema:
            type: string
          description: "The magic link token sent to the user's email."
          example: abc123def456ghi789
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      token:
                        type: string
              example:
                message: 'User Logged In Successfully'
                data:
                  token: 2|BeLWgqvfWsJTftMZ8mp2LGKdTUUCYb1HpFQJciEjb96187d8
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /passwordless/login:
    post:
      tags:
        - Auth
      summary: 'Request Passwordless Login Code'
      operationId: postAuthPasswordlessLogin
      description: 'Sends a one-time login code to the provided email address. The code expires after a configured timeout.'
      security: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
            example:
              email: user@example.com
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  expires_in:
                    type: integer
                    description: 'Number of seconds until the code expires.'
              example:
                success: true
                expires_in: 900
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /passwordless/verify:
    post:
      tags:
        - Auth
      summary: 'Verify Passwordless Login Code'
      operationId: postAuthPasswordlessVerify
      description: 'Verifies a one-time login code for the given email and returns an auth token on success.'
      security: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - code
              properties:
                email:
                  type: string
                  format: email
                code:
                  type: string
                  description: "The 6-digit one-time login code sent to the user's email."
                  minLength: 6
                  maxLength: 6
            example:
              email: user@example.com
              code: '123456'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      token:
                        type: string
              example:
                message: 'User Logged In Successfully'
                data:
                  token: 2|BeLWgqvfWsJTftMZ8mp2LGKdTUUCYb1HpFQJciEjb96187d8
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /passwordless/resend:
    post:
      tags:
        - Auth
      summary: 'Resend Passwordless Login Code'
      operationId: postAuthPasswordlessResend
      description: 'Resends a one-time login code to the provided email address, subject to a cooldown period.'
      security: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
            example:
              email: user@example.com
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  expires_in:
                    type: integer
                    description: 'Number of seconds until the new code expires.'
              example:
                success: true
                expires_in: 900
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /request-password-reset:
    post:
      tags:
        - Auth
      summary: 'Request a password reset email'
      operationId: postAuthRequestPasswordReset
      description: 'Sends a password reset email to the provided address. Requires HPP API key authentication.'
      security:
        -
          ApiKeyAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
            example:
              email: user@example.com
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Password reset email sent successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /reset-password:
    post:
      tags:
        - Auth
      summary: 'Reset Password'
      operationId: postAuthResetPassword
      description: "Resets the user's password using a valid reset token. Requires HPP API key authentication."
      security:
        -
          ApiKeyAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - token
                - password
              properties:
                token:
                  type: string
                  description: 'The password reset token received by email.'
                password:
                  type: string
                  format: password
                  description: 'The new password to set.'
            example:
              token: abc123def456ghi789jkl012mno345pqr
              password: newStrongPassword123
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Password has been reset successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /edit-password:
    post:
      tags:
        - Auth
      summary: 'Set a new password'
      operationId: postAuthEditPassword
      description: "Changes the authenticated user's password by verifying the old password and setting a new one. Requires HPP API key authentication."
      security:
        -
          ApiKeyAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - old_password
                - new_password
              properties:
                old_password:
                  type: string
                  format: password
                  description: "The user's current password."
                new_password:
                  type: string
                  format: password
                  description: 'The new password to set.'
            example:
              old_password: currentPassword123
              new_password: newStrongPassword456
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Password updated successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /caller-identities:
    get:
      tags:
        - CallerIdentities
      summary: 'List Caller Identities for the authenticated user'
      operationId: listCallerIdentities
      description: |
        Returns a paginated list of caller identities. Use the standard `search`, `sort`, `page`,
        and `perPage` query parameters; use `filter[key]=value` to narrow the result set.
        Multi-tenant scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        An outbound caller identity: the phone number (plus optional suffix and label)
                        shown to the called party when this entity places a call. Each identity is
                        attached to exactly one target (`User`, `Pbx`, `Group`, or `SipDevice`).
                        This table has no `timestamps`.
                      required:
                        - id
                        - pbx_id
                        - phone_number_id
                        - caller_identity_target_type
                        - caller_identity_target_id
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Caller identity identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        phone_number_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the PhoneNumber used as the outbound CID'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        suffix:
                          type:
                            - string
                            - 'null'
                          description: 'Optional digit suffix appended to the base phone number'
                          example: '23'
                        label:
                          type:
                            - string
                            - 'null'
                          description: 'Human-readable label shown in the admin UI'
                          example: 'Sales line'
                        caller_identity_target_type:
                          type: string
                          description: |
                            Polymorphic morph class for the entity this identity is attached to.
                            Stored as a fully qualified PHP class name.
                          enum:
                            - App\Models\User
                            - App\Models\Pbx
                            - App\Models\Group
                            - App\Models\SipDevice
                          example: App\Models\User
                        caller_identity_target_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the target entity'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        order:
                          type: integer
                          description: "Display order within the target's caller identity list"
                          example: 1
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    phone_number_id: 550e8400-e29b-41d4-a716-446655440002
                    suffix: '23'
                    label: 'Sales line'
                    caller_identity_target_type: App\Models\User
                    caller_identity_target_id: 550e8400-e29b-41d4-a716-446655440003
                    order: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  '/caller-identities/{id}':
    get:
      tags:
        - CallerIdentities
      summary: 'Get a caller Identity'
      operationId: getCallerIdentity
      description: |
        Returns the caller identity identified by the path parameter. Multi-tenant scoping is
        enforced: the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
          description: 'UUID of the caller identity'
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      An outbound caller identity: the phone number (plus optional suffix and label)
                      shown to the called party when this entity places a call. Each identity is
                      attached to exactly one target (`User`, `Pbx`, `Group`, or `SipDevice`).
                      This table has no `timestamps`.
                    required:
                      - id
                      - pbx_id
                      - phone_number_id
                      - caller_identity_target_type
                      - caller_identity_target_id
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Caller identity identifier'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Pbx identifier (tenant)'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      phone_number_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PhoneNumber used as the outbound CID'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      suffix:
                        type:
                          - string
                          - 'null'
                        description: 'Optional digit suffix appended to the base phone number'
                        example: '23'
                      label:
                        type:
                          - string
                          - 'null'
                        description: 'Human-readable label shown in the admin UI'
                        example: 'Sales line'
                      caller_identity_target_type:
                        type: string
                        description: |
                          Polymorphic morph class for the entity this identity is attached to.
                          Stored as a fully qualified PHP class name.
                        enum:
                          - App\Models\User
                          - App\Models\Pbx
                          - App\Models\Group
                          - App\Models\SipDevice
                        example: App\Models\User
                      caller_identity_target_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the target entity'
                        example: 550e8400-e29b-41d4-a716-446655440003
                      order:
                        type: integer
                        description: "Display order within the target's caller identity list"
                        example: 1
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id: 550e8400-e29b-41d4-a716-446655440001
                  phone_number_id: 550e8400-e29b-41d4-a716-446655440002
                  suffix: '23'
                  label: 'Sales line'
                  caller_identity_target_type: App\Models\User
                  caller_identity_target_id: 550e8400-e29b-41d4-a716-446655440003
                  order: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /call-flows:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - CallFlows
      summary: 'List Call flow'
      operationId: listCallFlows
      description: |
        Returns a paginated list of call flows. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `enabled`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        A named, ordered sequence of routing rules applied to inbound (and internal)
                        calls on a tenant. A CallFlow groups the individual routing steps that decide
                        where a call goes (IVR menus, queues, extensions, schedules, voicemail, and so
                        on). This read-only API shape exposes the curated CallFlow header fields only:
                        the ordered step list, the internal checksum, and soft-delete timestamp are not
                        returned here.
                      required:
                        - id
                        - pbx_id
                        - name
                        - enabled
                        - version
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique call flow identifier.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this call flow.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type: string
                          description: 'Human-readable label for the call flow, shown in lists and pickers.'
                          example: 'Main inbound flow'
                        description:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-text note describing the purpose of the call flow.'
                          example: 'Routes incoming calls to support, then voicemail.'
                        enabled:
                          type: boolean
                          description: 'Whether the call flow is active. Disabled flows are not applied to calls.'
                          example: true
                        version:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          minimum: 0
                          description: |
                            Version counter for the call flow. Set to 1 when the flow is created and
                            bumped on subsequent saves, allowing integrators to detect changes.
                          example: 7
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601) when the call flow was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601) when the call flow was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - CallFlows
      summary: 'Create a call flow'
      operationId: createCallFlow
      description: |
        Create a call flow. Only `name`, `description` and `enabled` are accepted; the PBX is
        taken from the authenticated token. Call flow steps are not part of this request: create
        them separately against `/call-flow-steps` once the call flow exists.
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 255
                  description: 'Name of the call flow.'
                description:
                  type:
                    - string
                    - 'null'
                  description: 'Optional free-form description.'
                enabled:
                  type: boolean
                  description: 'Whether the call flow is active. Falls back to the model default when omitted.'
            example:
              name: 'Main inbound flow'
              description: 'Routes incoming calls to support, then voicemail'
              enabled: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                description: |
                  A named, ordered sequence of routing rules applied to inbound (and internal)
                  calls on a tenant. A CallFlow groups the individual routing steps that decide
                  where a call goes (IVR menus, queues, extensions, schedules, voicemail, and so
                  on). This read-only API shape exposes the curated CallFlow header fields only:
                  the ordered step list, the internal checksum, and soft-delete timestamp are not
                  returned here.
                required:
                  - id
                  - pbx_id
                  - name
                  - enabled
                  - version
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique call flow identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this call flow.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    description: 'Human-readable label for the call flow, shown in lists and pickers.'
                    example: 'Main inbound flow'
                  description:
                    type:
                      - string
                      - 'null'
                    description: 'Optional free-text note describing the purpose of the call flow.'
                    example: 'Routes incoming calls to support, then voicemail.'
                  enabled:
                    type: boolean
                    description: 'Whether the call flow is active. Disabled flows are not applied to calls.'
                    example: true
                  version:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    minimum: 0
                    description: |
                      Version counter for the call flow. Set to 1 when the flow is created and
                      bumped on subsequent saves, allowing integrators to detect changes.
                    example: 7
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601) when the call flow was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601) when the call flow was last updated.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/call-flows/{call_flow}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - CallFlows
      summary: 'Get a Call flow'
      operationId: getCallFlow
      description: |
        Returns the call flow identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  A named, ordered sequence of routing rules applied to inbound (and internal)
                  calls on a tenant. A CallFlow groups the individual routing steps that decide
                  where a call goes (IVR menus, queues, extensions, schedules, voicemail, and so
                  on). This read-only API shape exposes the curated CallFlow header fields only:
                  the ordered step list, the internal checksum, and soft-delete timestamp are not
                  returned here.
                required:
                  - id
                  - pbx_id
                  - name
                  - enabled
                  - version
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique call flow identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this call flow.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    description: 'Human-readable label for the call flow, shown in lists and pickers.'
                    example: 'Main inbound flow'
                  description:
                    type:
                      - string
                      - 'null'
                    description: 'Optional free-text note describing the purpose of the call flow.'
                    example: 'Routes incoming calls to support, then voicemail.'
                  enabled:
                    type: boolean
                    description: 'Whether the call flow is active. Disabled flows are not applied to calls.'
                    example: true
                  version:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    minimum: 0
                    description: |
                      Version counter for the call flow. Set to 1 when the flow is created and
                      bumped on subsequent saves, allowing integrators to detect changes.
                    example: 7
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601) when the call flow was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601) when the call flow was last updated.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /call-flow-steps:
    get:
      tags:
        - CallFlowSteps
      summary: 'List Call flow step'
      operationId: listCallFlowSteps
      description: |
        Returns a paginated list of call flow steps. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, pbx_id, call_flow_id, type, options, is_active and order.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      description: |
                        A single step inside a call flow. Steps are evaluated in ascending `order`
                        to drive how an inbound call is handled. The `type` field discriminates the
                        shape of `options`: each variant below documents the keys carried in
                        `options` for that particular step type. Variants with no configurable
                        settings (`hang_up`, `start_recording`, `answer`) use an empty options
                        object. The v1 API returns exactly these top-level fields on every variant:
                        `id`, `pbx_id`, `call_flow_id`, `type`, `options`, `is_active`, `order`.
                        Most ID references inside `options` are UUIDs of related resources (users,
                        groups, IVRs, queues, schedules, etc.) scoped to the same tenant.
                      oneOf:
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (ring_user)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - ring_user
                              description: 'Step type. For this variant it rings one or more cockpit users, SIP devices, or groups.'
                              example: ring_user
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings describing which targets to ring and for how long.'
                              required:
                                - duration
                              properties:
                                duration:
                                  type: integer
                                  format: int32
                                  minimum: 1
                                  description: 'Ring duration in seconds before moving to the next step.'
                                  example: 20
                                also_ring_dialed_extension:
                                  type: boolean
                                  description: 'When true, also rings the extension that was originally dialed.'
                                  example: false
                                also_ring_everyone_in_the_user_group:
                                  type: boolean
                                  description: "When true, also rings every member of the dialed user's group."
                                  example: false
                                dial_mobile_twinnings:
                                  type: boolean
                                  description: 'When true, also rings the mobile twinning numbers configured for the targets.'
                                  example: false
                                missed_calls:
                                  type: boolean
                                  description: 'When true, an unanswered call on this step counts as a missed call for the targets. Defaults to true.'
                                  example: true
                                music_on_hold:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the music-on-hold playlist played while ringing.'
                                  example: 550e8400-e29b-41d4-a716-446655440010
                                users:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of the users to ring.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440011
                                sip_devices:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of the SIP devices to ring.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440012
                                groups:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of the user groups to ring.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440013
                                tags:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of tags whose tagged users should be rung.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440014
                                locations:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of locations whose users should be rung.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440015
                                languages:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of languages used to select which users to ring.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440016
                                pools:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of pools whose users should be rung.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440017
                                statuses:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of Tempus statuses used to filter which users are rung.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440018
                                pickup_lines:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of users whose calls may be picked up by this step.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440019
                                sub_statuses:
                                  type:
                                    - object
                                    - 'null'
                                  description: |
                                    Map keyed by Tempus status UUID. Each value is the list of
                                    Tempus sub-status UUIDs selected under that status.
                                  additionalProperties:
                                    type: array
                                    items:
                                      type: string
                                      format: uuid
                                  example:
                                    550e8400-e29b-41d4-a716-446655440018:
                                      - 550e8400-e29b-41d4-a716-446655440020
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (ring_external_number)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - ring_external_number
                              description: 'Step type. For this variant it dials out to an external PSTN number.'
                              example: ring_external_number
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 1
                            options:
                              type: object
                              description: 'Settings describing the external number to dial.'
                              properties:
                                duration:
                                  type: integer
                                  format: int32
                                  minimum: 1
                                  description: 'Ring duration in seconds before moving to the next step.'
                                  example: 30
                                number:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'External destination number in E.164 format.'
                                  example: '+12125550100'
                                music_on_hold:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the music-on-hold playlist played while ringing.'
                                  example: 550e8400-e29b-41d4-a716-446655440010
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (call_flow)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - call_flow
                              description: 'Step type. For this variant it routes the call to another call flow or extension.'
                              example: call_flow
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 2
                            options:
                              type: object
                              description: 'Settings describing the destination and optional schedule.'
                              required:
                                - call_flow_or_extension
                              properties:
                                call_flow_or_extension:
                                  type: string
                                  enum:
                                    - extension
                                    - call_flow
                                  description: 'Selects whether the call is routed to an extension or another call flow.'
                                  example: call_flow
                                extension:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the destination extension (used when routing to an extension).'
                                  example: 550e8400-e29b-41d4-a716-446655440030
                                call_flow:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the destination call flow (used when routing to a call flow).'
                                  example: 550e8400-e29b-41d4-a716-446655440031
                                schedule:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of a schedule that gates when this routing applies.'
                                  example: 550e8400-e29b-41d4-a716-446655440032
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (go_to_ivr)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - go_to_ivr
                              description: 'Step type. For this variant it hands the call off to an IVR menu.'
                              example: go_to_ivr
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings identifying which IVR to enter.'
                              properties:
                                ivr:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the IVR menu to enter.'
                                  example: 550e8400-e29b-41d4-a716-446655440040
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (enter_queue)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - enter_queue
                              description: 'Step type. For this variant it parks the caller in a queue.'
                              example: enter_queue
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 1
                            options:
                              type: object
                              description: 'Settings identifying the queue and how long to wait.'
                              properties:
                                duration:
                                  type: integer
                                  format: int32
                                  minimum: 1
                                  description: 'Maximum time in seconds to keep the caller queued before moving on.'
                                  example: 60
                                queue:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the queue to enter.'
                                  example: 550e8400-e29b-41d4-a716-446655440050
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (text_to_speech)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - text_to_speech
                              description: 'Step type. For this variant it plays an announcement (sound file or synthesized speech).'
                              example: text_to_speech
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings describing the announcement source.'
                              required:
                                - announcement_type
                              properties:
                                announcement_type:
                                  type: string
                                  enum:
                                    - sound_file
                                    - tts_tag
                                    - tts_message
                                  description: 'Selects the announcement source (a stored sound file, a TTS tag, or a free-text TTS message).'
                                  example: tts_message
                                sound_file:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the announcement sound file to play (used when announcement_type is sound_file).'
                                  example: 550e8400-e29b-41d4-a716-446655440060
                                language:
                                  type:
                                    - string
                                    - 'null'
                                  description: |
                                    Announcement language override. `null` (Auto) plays the variant for the
                                    language detected/inherited earlier in the call; otherwise an ISO-639-1 code
                                    forces that variant.
                                  enum:
                                    - en
                                    - de
                                    - fr
                                    - lb
                                    - es
                                    - it
                                    - pt
                                    - nl
                                    - pl
                                    - ru
                                    - tr
                                    - sv
                                    - da
                                    - 'no'
                                    - fi
                                    - cs
                                    - sk
                                    - el
                                    - hu
                                    - ro
                                    - bg
                                    - hr
                                    - uk
                                    - ar
                                    - he
                                    - hi
                                    - ja
                                    - ko
                                    - zh
                                    - id
                                    - ms
                                    - th
                                    - vi
                                    - null
                                  example: fr
                                tts_tag:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Predefined TTS tag identifying a templated message (used when announcement_type is tts_tag).'
                                  example: greeting_morning
                                tts_message:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Free-text message to synthesize and play (used when announcement_type is tts_message).'
                                  example: 'Welcome to Customer Support.'
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (change_ringtone_and_label)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - change_ringtone_and_label
                              description: 'Step type. For this variant it overrides the ringtone and the caller display label.'
                              example: change_ringtone_and_label
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings overriding ringtone, label, and music on hold.'
                              properties:
                                ringtone:
                                  type:
                                    - string
                                    - 'null'
                                  enum:
                                    - alert-ring1
                                    - alert-ring2
                                    - alert-ring3
                                    - alert-ring4
                                    - alert-ring5
                                    - 'null'
                                  description: 'Ringtone key to apply on the receiving device.'
                                  example: alert-ring1
                                label:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Display label shown to the called party for the incoming call.'
                                  example: VIP
                                music_on_hold:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the music-on-hold playlist to apply.'
                                  example: 550e8400-e29b-41d4-a716-446655440010
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (webhook)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - webhook
                              description: 'Step type. For this variant it fires an outbound HTTP request mid-flow.'
                              example: webhook
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 2
                            options:
                              type: object
                              description: 'Settings describing the HTTP endpoint to call.'
                              properties:
                                url:
                                  type:
                                    - string
                                    - 'null'
                                  format: uri
                                  description: 'HTTP(S) endpoint invoked when the step runs.'
                                  example: 'https://cockpit.voxbi.com/hooks/call'
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (send_to_email)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - send_to_email
                              description: 'Step type. For this variant it emails a recording/voicemail to recipients.'
                              example: send_to_email
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 3
                            options:
                              type: object
                              description: 'Settings describing the recording to attach and the recipients.'
                              properties:
                                sound_file:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the sound file (recording) to attach to the email.'
                                  example: 550e8400-e29b-41d4-a716-446655440060
                                language:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Announcement language override; `null` (Auto) keeps the detected/inherited language.'
                                  enum:
                                    - en
                                    - de
                                    - fr
                                    - lb
                                    - es
                                    - it
                                    - pt
                                    - nl
                                    - pl
                                    - ru
                                    - tr
                                    - sv
                                    - da
                                    - 'no'
                                    - fi
                                    - cs
                                    - sk
                                    - el
                                    - hu
                                    - ro
                                    - bg
                                    - hr
                                    - uk
                                    - ar
                                    - he
                                    - hi
                                    - ja
                                    - ko
                                    - zh
                                    - id
                                    - ms
                                    - th
                                    - vi
                                    - null
                                  example: fr
                                email:
                                  type:
                                    - string
                                    - 'null'
                                  format: email
                                  description: 'Explicit recipient email address.'
                                  example: support@example.com
                                email_user:
                                  type:
                                    - array
                                    - 'null'
                                  description: 'Identifiers of users whose email addresses should receive the message.'
                                  items:
                                    type: string
                                    format: uuid
                                  example:
                                    - 550e8400-e29b-41d4-a716-446655440011
                                email_to_called_user:
                                  type: boolean
                                  description: 'When true, also emails the user who was originally called.'
                                  example: false
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (conference_room)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - conference_room
                              description: 'Step type. For this variant it drops the caller into a conference room.'
                              example: conference_room
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings identifying the conference room extension.'
                              properties:
                                extension:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the extension hosting the conference room.'
                                  example: 550e8400-e29b-41d4-a716-446655440030
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (ivr_extension)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - ivr_extension
                              description: 'Step type. For this variant it plays a sound and waits for IVR-style key input.'
                              example: ivr_extension
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings identifying the sound file to play.'
                              properties:
                                sound_file:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the sound file to play before collecting input.'
                                  example: 550e8400-e29b-41d4-a716-446655440060
                                language:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Announcement language override; `null` (Auto) keeps the detected/inherited language.'
                                  enum:
                                    - en
                                    - de
                                    - fr
                                    - lb
                                    - es
                                    - it
                                    - pt
                                    - nl
                                    - pl
                                    - ru
                                    - tr
                                    - sv
                                    - da
                                    - 'no'
                                    - fi
                                    - cs
                                    - sk
                                    - el
                                    - hu
                                    - ro
                                    - bg
                                    - hr
                                    - uk
                                    - ar
                                    - he
                                    - hi
                                    - ja
                                    - ko
                                    - zh
                                    - id
                                    - ms
                                    - th
                                    - vi
                                    - null
                                  example: fr
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (multicast)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - multicast
                              description: 'Step type. For this variant it pages a multicast (intercom) group.'
                              example: multicast
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings identifying the multicast group and access PIN.'
                              properties:
                                multicast_group:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Name or identifier of the multicast paging group.'
                                  example: paging-floor-1
                                multicast_pin:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'PIN required to join the multicast group.'
                                  example: '1234'
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (ai_assistant)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - ai_assistant
                              description: 'Step type. For this variant it hands the call off to a Smart IVR / AI agent.'
                              example: ai_assistant
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              description: 'Settings identifying the AI provider and agent.'
                              properties:
                                ai_provider:
                                  type: string
                                  enum:
                                    - famulor
                                  description: 'AI provider backing the assistant.'
                                  example: famulor
                                famulor_agent:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Identifier of the Famulor agent that handles the call.'
                                  example: 550e8400-e29b-41d4-a716-446655440070
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (hang_up)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - hang_up
                              description: 'Step type. For this variant it terminates the call. This step has no configurable options.'
                              example: hang_up
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 4
                            options:
                              type: object
                              additionalProperties: false
                              description: 'Empty options object (this step type has no settings).'
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (start_recording)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - start_recording
                              description: 'Step type. For this variant it begins call recording. This step has no configurable options.'
                              example: start_recording
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              additionalProperties: false
                              description: 'Empty options object (this step type has no settings).'
                        -
                          type: object
                          required:
                            - id
                            - pbx_id
                            - call_flow_id
                            - type
                            - options
                            - is_active
                            - order
                          title: 'CallFlowStep (answer)'
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the call flow step'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the PBX (tenant) this step belongs to'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            call_flow_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent call flow that owns this step'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            type:
                              type: string
                              enum:
                                - answer
                              description: 'Step type. For this variant it explicitly answers the call. This step has no configurable options.'
                              example: answer
                            is_active:
                              type: boolean
                              description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                              example: true
                            order:
                              type: integer
                              format: int32
                              minimum: 0
                              description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                              example: 0
                            options:
                              type: object
                              additionalProperties: false
                              description: 'Empty options object (this step type has no settings).'
                      discriminator:
                        propertyName: type
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    call_flow_id: 550e8400-e29b-41d4-a716-446655440002
                    type: ring_user
                    options:
                      duration: 20
                      also_ring_dialed_extension: false
                      also_ring_everyone_in_the_user_group: false
                      dial_mobile_twinnings: false
                      missed_calls: true
                      music_on_hold: 550e8400-e29b-41d4-a716-446655440000
                      users:
                        - 550e8400-e29b-41d4-a716-446655440000
                      sip_devices:
                        - 550e8400-e29b-41d4-a716-446655440000
                      groups:
                        - 550e8400-e29b-41d4-a716-446655440000
                      tags:
                        - 550e8400-e29b-41d4-a716-446655440000
                      locations:
                        - 550e8400-e29b-41d4-a716-446655440000
                      languages:
                        - 550e8400-e29b-41d4-a716-446655440000
                      pools:
                        - 550e8400-e29b-41d4-a716-446655440000
                      statuses:
                        - 550e8400-e29b-41d4-a716-446655440000
                      pickup_lines:
                        - 550e8400-e29b-41d4-a716-446655440000
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /calls/new:
    post:
      tags:
        - Calls
      summary: 'Initiate a new call'
      operationId: postCallNew
      description: |
        Places an outbound call on behalf of the authenticated user.

        ## Minimal request

        `destination` is the only required field. Everything else is optional:

        ```json
        { "destination": "+12125550199" }
        ```

        With nothing else supplied, the call is placed using the user's own configuration: their
        default caller identity and their default ringing targets as set up in the cockpit.

        ## Choosing target devices

        Send `targets` when you want to override which of the user's endpoints should ring. Each
        flag is independent, so you can combine them (for example ring the desk phone and the
        twinned mobile at the same time):

        ```json
        {
          "destination": "+12125550199",
          "targets": {
            "sip_devices": [],
            "webrtc": false,
            "twinning": true,
            "teams": false
          }
        }
        ```

        - `sip_devices`: list of SIP device identifiers to ring. Omit or send `null` to let the PBX
          pick the user's SIP devices.
        - `webrtc`: ring the browser softphone. Defaults to `false`.
        - `twinning`: ring the twinned (mobile) number. Defaults to `false`.
        - `teams`: ring the Microsoft Teams endpoint. Defaults to `false`.

        Every boolean flag defaults to `false` when it is not passed, so a `targets` object is only
        useful if at least one flag is `true` or `sip_devices` is populated.

        Enabling a target only has an effect if the matching configuration or integration exists for
        the user: WebRTC requires a WebRTC-enabled account, `twinning` requires a twinning number,
        and `teams` requires the Teams integration. If the underlying feature is not configured, the
        PBX simply skips that target and rings whatever remains.

        ## Caller identity

        `caller_identity` is optional. Pass the UUID of a caller identity available to the user to
        present a specific outbound number. When omitted, the user's default caller identity is
        used.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: debugAmiTrace
          in: query
          schema:
            type: boolean
          required: false
          description: 'Enable AMI trace for debugging'
        -
          name: autoAnswer
          in: query
          schema:
            type: boolean
          required: false
          description: 'Auto-answer the call'
        -
          name: forceDialBack
          in: query
          schema:
            type: boolean
          required: false
          description: 'Force dial-back mode'
        -
          name: anonymous
          in: query
          schema:
            type: boolean
          required: false
          description: 'Make the call anonymous'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - destination
              properties:
                destination:
                  type: string
                  description: |
                    The number or extension to dial. This is the only required field: a request
                    carrying nothing but `destination` places a valid call.
                  example: '+12125550199'
                caller_identity:
                  type: string
                  format: uuid
                  description: |
                    Optional. UUID of the caller identity (root number or identity) to present for
                    this call. Pass it only when this call should go out with a different identity
                    than usual. When omitted, the user's default caller identity is used.
                  example: 550e8400-e29b-41d4-a716-446655440000
                targets:
                  type: object
                  description: |
                    Optional. Overrides which of the user's endpoints ring. Omit the whole object to
                    use the user's configured targets. Every boolean defaults to `false` when not
                    passed, so at least one flag should be `true` (or `sip_devices` populated) for a
                    `targets` object to be meaningful. A flag only takes effect when the matching
                    configuration or integration exists for the user; otherwise the PBX skips that
                    target.
                  properties:
                    sip_devices:
                      type:
                        - array
                        - 'null'
                      description: |
                        SIP device identifiers to ring. Omit or send `null` to let the PBX resolve
                        the user's SIP devices.
                      items:
                        type: string
                      example: null
                    webrtc:
                      type: boolean
                      description: 'Ring the browser softphone. Defaults to `false`.'
                      example: false
                    twinning:
                      type: boolean
                      description: 'Ring the twinned (mobile) number. Defaults to `false`.'
                      example: false
                    teams:
                      type: boolean
                      description: 'Ring the Microsoft Teams endpoint. Defaults to `false`.'
                      example: false
            examples:
              minimal:
                summary: 'Simple call, destination only'
                description: |
                  The smallest valid request. The user's default caller identity and configured targets are used.
                value:
                  destination: '+12125550199'
              withTargets:
                summary: 'Call ringing a specific set of targets'
                description: |
                  Rings the twinned mobile instead of the default set. Flags left at `false` (and an empty `sip_devices`) are not rung.
                value:
                  destination: '+12125550199'
                  targets:
                    sip_devices: {}
                    webrtc: false
                    twinning: true
                    teams: false
              withCallerIdentity:
                summary: 'Call presenting a specific caller identity'
                description: |
                  Uses a different root number or identity for this call only, leaving the user's default untouched.
                value:
                  destination: '+12125550199'
                  caller_identity: 550e8400-e29b-41d4-a716-446655440000
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
                  data:
                    type: object
              example:
                status: success
                message: 'Call initiated successfully.'
                data:
                  call_id: abc123
                  destination: '+12125550199'
        400:
          description: 'Bad Request'
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: error
                message: 'User PBX instance not found.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
        500:
          description: 'Internal Server Error'
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: error
                message: 'Failed to initiate call.'
  /ai-configuration:
    get:
      tags:
        - AiConfiguration
      summary: 'Get AI configuration (pbx)'
      operationId: getAiConfiguration
      description: |
        Returns the PBX's aggregated, read-only AI configuration: the account-wide
        global prompt and labels, the classification keyword tree, per-extension and
        per-group prompts, and the active AI profile and feature flags.

        Requires a PBX "API key" carrying the `ai-configuration` scope. The PBX is
        resolved from the token.
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Aggregated, read-only AI configuration for a PBX: the account-wide global
                  prompt and labels, the classification keyword tree, per-extension and
                  per-group prompts, and the active AI profile and feature flags.
                required:
                  - pbx_id
                  - ai_features
                properties:
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  ai_profile:
                    type:
                      - string
                      - 'null'
                    description: 'Active AI plan for the PBX (null when the PBX is not on an AI plan)'
                    enum:
                      - unlimited
                      - basic
                      - premium
                      - null
                    example: premium
                  ai_features:
                    type: object
                    description: 'Enabled AI feature flags for the PBX'
                    properties:
                      summary:
                        type: boolean
                        example: true
                      transcription:
                        type: boolean
                        example: true
                      translations:
                        type: boolean
                        example: false
                      keyword_mapping_to_call:
                        type: boolean
                        example: false
                      tagging_calls:
                        type: boolean
                        example: false
                      sentiment_analysis:
                        type: boolean
                        example: false
                  global_prompt:
                    type:
                      - string
                      - 'null'
                    description: 'Account-wide prompt every AI tool reads as ground truth'
                    example: 'You are the AI assistant for Example Corp. Be concise and polite.'
                  labels:
                    type: array
                    description: 'Reusable classification labels, in display order'
                    items:
                      type: string
                    example:
                      - Sales
                      - Support
                      - Billing
                  keywords:
                    type: array
                    description: |
                      Hierarchical classification keywords. Each node carries an optional rule `prompt` and a `children` array of the same shape (recursively nested).
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440010
                        name:
                          type: string
                          example: Billing
                        prompt:
                          type:
                            - string
                            - 'null'
                          description: 'The rule that tells the classifier when to apply this keyword'
                          example: 'Apply when the caller asks about invoices or payments.'
                        children:
                          type: array
                          description: 'Nested child keywords, each of the same shape'
                          items:
                            type: object
                  extension_prompts:
                    type: array
                    description: 'Per-extension AI prompts'
                    items:
                      type: object
                      properties:
                        extension_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440020
                        extension:
                          type:
                            - string
                            - 'null'
                          description: 'The extension number the prompt is attached to'
                          example: '101'
                        prompt:
                          type: string
                          example: 'Greet callers as the reception desk and offer to take a message.'
                  group_prompts:
                    type: array
                    description: 'Per-group AI prompts'
                    items:
                      type: object
                      properties:
                        group_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440030
                        group:
                          type:
                            - string
                            - 'null'
                          description: 'The group name the prompt is attached to'
                          example: Support
                        prompt:
                          type: string
                          example: "Prioritise urgent tickets and confirm the caller's contract number."
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The API key does not carry the `ai-configuration` scope.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
  /contacts:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Contacts
      summary: 'List contact'
      operationId: listContacts
      description: |
        Returns a paginated list of contacts. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `id`, `name1`, `name2`, `email`, `company_name`, `department`, `job_title`, `is_private`, `is_blocked_globally`, `private_owner_id`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
        -
          name: include
          description: |
            Comma-separated related resources to embed (dot-nested where
            shown). Allowed: `numbers`, `groups`, `blockedByUsers`.
          in: query
          required: false
          schema:
            type: string
          example: 'numbers,groups'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Shared or personal address book entry. Phone numbers are held on the related
                        `numbers` records. `handling_strategy` carries the polymorphic redirect target
                        when inbound calls from this contact should be steered to a specific
                        destination.
                      required:
                        - id
                        - pbx_id
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Contact identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        company_name:
                          type:
                            - string
                            - 'null'
                          example: 'Acme Corp'
                        department:
                          type:
                            - string
                            - 'null'
                          example: Engineering
                        job_title:
                          type:
                            - string
                            - 'null'
                          example: 'Head of Product'
                        name1:
                          type:
                            - string
                            - 'null'
                          description: 'Primary name (first name, given name)'
                          example: Jane
                        name2:
                          type:
                            - string
                            - 'null'
                          description: 'Secondary name (last name, surname)'
                          example: Smith
                        email:
                          type:
                            - string
                            - 'null'
                          format: email
                          example: jane.smith@example.com
                        notes:
                          type:
                            - string
                            - 'null'
                          example: 'Calls every Monday morning'
                        vip:
                          type: boolean
                          description: 'Whether the contact is flagged as VIP'
                          example: false
                        numbers:
                          type: array
                          description: |
                            Phone numbers attached to this contact. Embed via `?include=numbers`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440010
                                readOnly: true
                              phone_number:
                                type: string
                                description: 'The phone number (E.164 preferred)'
                                example: '+12125550100'
                              label:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional label for the number'
                                example: 'Direct line'
                              type:
                                type: string
                                description: 'Kind of phone number'
                                enum:
                                  - business
                                  - mobile
                                  - other
                                  - fax
                                example: business
                              speed_dial:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional speed-dial code for this number'
                                example: '201'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        is_private:
                          type: boolean
                          description: 'Private contacts are visible only to their `private_owner_id` user'
                          example: false
                        private_owner_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Owner user when `is_private` is true'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        editable:
                          type: boolean
                          description: |
                            Whether the **calling user** may edit this contact.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (which own all of their contacts).
                          example: true
                        is_favorite:
                          type: boolean
                          description: |
                            Whether this contact is one of the **calling user's** favourites.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                          example: false
                        groups:
                          type: array
                          description: |
                            Groups this contact belongs to. Embed via `?include=groups`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        is_blocked_globally:
                          type: boolean
                          description: 'Whether inbound calls from this contact are blocked tenant-wide'
                          example: false
                        blocked_by_users:
                          type: array
                          description: |
                            Users who have personally blocked this contact, each as a user reference.
                            Embed via `?include=blockedByUsers`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                        handling_strategy:
                          type:
                            - object
                            - 'null'
                          description: |
                            Optional polymorphic redirect target applied to inbound calls from this
                            contact. `type` discriminates which `*_id` field is meaningful.
                          properties:
                            type:
                              type: string
                              enum:
                                - call_flow
                                - extension
                                - user
                                - sip_device
                              example: call_flow
                            call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            extension_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            user_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            sip_device_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - Contacts
      summary: 'Create a contact'
      operationId: createContact
      description: |
        Create an address-book contact. A contact is either private (owned by
        `private_owner_id`) or shared with a set of `groups` (the two are
        mutually exclusive). Phone numbers are sent in the nested
        `contactPhoneNumbers[]` array. `is_private` is derived from
        `private_owner_id` server-side and must not be sent.

        The optional `handling_strategy` defines per-contact inbound routing.
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name1
              properties:
                name1:
                  type: string
                  minLength: 3
                  maxLength: 64
                  description: 'Primary name (first / given name)'
                name2:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 64
                  description: 'Secondary name (last / surname)'
                email:
                  type:
                    - string
                    - 'null'
                  format: email
                  maxLength: 50
                company_name:
                  type:
                    - string
                    - 'null'
                  minLength: 2
                  maxLength: 64
                department:
                  type:
                    - string
                    - 'null'
                  minLength: 2
                  maxLength: 64
                job_title:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 32
                notes:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                private_owner_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'When set, contact is private and visible only to this user. Mutually exclusive with `groups`.'
                groups:
                  type: array
                  description: 'Groups this contact is shared with. Mutually exclusive with `private_owner_id`.'
                  items:
                    type: string
                    format: uuid
                contactPhoneNumbers:
                  type: array
                  minItems: 1
                  description: 'Phone numbers attached to the contact. When present, must contain at least one entry.'
                  items:
                    type: object
                    required:
                      - phone_number
                      - type
                    properties:
                      phone_number:
                        type: string
                        pattern: '^\+?\d*$'
                        maxLength: 24
                      label:
                        type:
                          - string
                          - 'null'
                        maxLength: 64
                      type:
                        type: string
                        description: 'Channel category (work, mobile, fax, etc.)'
                      speed_dial:
                        type:
                          - string
                          - 'null'
                        description: 'Speed-dial code (auto-prefixed with `*#`)'
                handling_strategy:
                  type:
                    - object
                    - 'null'
                  description: 'Optional inbound-routing override for calls from this contact'
                  additionalProperties: true
            example:
              name1: Jane
              name2: Smith
              email: jane.smith@example.com
              company_name: 'Acme Corp'
              department: Engineering
              job_title: 'Head of Product'
              notes: 'Calls every Monday morning'
              groups:
                - 550e8400-e29b-41d4-a716-446655440010
              contactPhoneNumbers:
                -
                  phone_number: '+12125550100'
                  label: Mobile
                  type: mobile
                  speed_dial: '12'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Shared or personal address book entry. Phone numbers are held on the related
                      `numbers` records. `handling_strategy` carries the polymorphic redirect target
                      when inbound calls from this contact should be steered to a specific
                      destination.
                    required:
                      - id
                      - pbx_id
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Contact identifier'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Pbx identifier (tenant)'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      company_name:
                        type:
                          - string
                          - 'null'
                        example: 'Acme Corp'
                      department:
                        type:
                          - string
                          - 'null'
                        example: Engineering
                      job_title:
                        type:
                          - string
                          - 'null'
                        example: 'Head of Product'
                      name1:
                        type:
                          - string
                          - 'null'
                        description: 'Primary name (first name, given name)'
                        example: Jane
                      name2:
                        type:
                          - string
                          - 'null'
                        description: 'Secondary name (last name, surname)'
                        example: Smith
                      email:
                        type:
                          - string
                          - 'null'
                        format: email
                        example: jane.smith@example.com
                      notes:
                        type:
                          - string
                          - 'null'
                        example: 'Calls every Monday morning'
                      vip:
                        type: boolean
                        description: 'Whether the contact is flagged as VIP'
                        example: false
                      numbers:
                        type: array
                        description: |
                          Phone numbers attached to this contact. Embed via `?include=numbers`.
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440010
                              readOnly: true
                            phone_number:
                              type: string
                              description: 'The phone number (E.164 preferred)'
                              example: '+12125550100'
                            label:
                              type:
                                - string
                                - 'null'
                              description: 'Optional label for the number'
                              example: 'Direct line'
                            type:
                              type: string
                              description: 'Kind of phone number'
                              enum:
                                - business
                                - mobile
                                - other
                                - fax
                              example: business
                            speed_dial:
                              type:
                                - string
                                - 'null'
                              description: 'Optional speed-dial code for this number'
                              example: '201'
                            created_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            updated_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                      is_private:
                        type: boolean
                        description: 'Private contacts are visible only to their `private_owner_id` user'
                        example: false
                      private_owner_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Owner user when `is_private` is true'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      editable:
                        type: boolean
                        description: |
                          Whether the **calling user** may edit this contact.
                          PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                          OMITTED entirely for PBX API-key tokens (which own all of their contacts).
                        example: true
                      is_favorite:
                        type: boolean
                        description: |
                          Whether this contact is one of the **calling user's** favourites.
                          PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                          OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                        example: false
                      groups:
                        type: array
                        description: |
                          Groups this contact belongs to. Embed via `?include=groups`.
                        items:
                          type: object
                          description: |
                            Group of users that share routing defaults and (optionally) a common caller
                            identity. Many fields are foreign keys pointing at defaults used when the
                            group's users place or receive calls.
                          required:
                            - id
                            - pbx_id
                            - name
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Group identifier'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Pbx identifier (tenant)'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            default_internal_call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Call flow used for internal calls reaching this group'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            default_external_call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Call flow used for external calls reaching this group'
                              example: 550e8400-e29b-41d4-a716-446655440003
                            extension_id_shown_outside_the_group:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Extension displayed to non-group members'
                              example: 550e8400-e29b-41d4-a716-446655440005
                            default_caller_identity_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: "Default caller identity applied to the group's outbound calls"
                              example: 550e8400-e29b-41d4-a716-446655440004
                            external_uid:
                              type:
                                - string
                                - 'null'
                              description: 'External identifier from a CRM or directory sync'
                              example: grp-support
                            allow_call_pickups:
                              type: boolean
                              description: "Whether group members may pick up each others' ringing calls"
                              example: true
                            name:
                              type: string
                              maxLength: 64
                              example: 'Support team'
                            description:
                              type:
                                - string
                                - 'null'
                              maxLength: 255
                              example: 'First-line support'
                            allow_default_pbxes_outgoing_phone_numbers:
                              type: boolean
                              description: "Whether the group's CIDs include the PBX-default outbound numbers"
                              example: false
                            display_tab_to_everyone_inside_voxbi:
                              type: boolean
                              description: "Whether the group's tab is shown to everyone in the PBX"
                              example: false
                            created_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            updated_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            users:
                              type: array
                              description: |
                                Members of the group, each as a user reference. Returned only when
                                requested via `?include=users`.
                              items:
                                type: object
                                properties:
                                  id:
                                    type: string
                                    format: uuid
                                    example: 550e8400-e29b-41d4-a716-446655440006
                                    readOnly: true
                                  first_name:
                                    type:
                                      - string
                                      - 'null'
                                    example: Jane
                                  last_name:
                                    type:
                                      - string
                                      - 'null'
                                    example: Smith
                                  email:
                                    type:
                                      - string
                                      - 'null'
                                    format: email
                                    example: jane.smith@example.com
                      is_blocked_globally:
                        type: boolean
                        description: 'Whether inbound calls from this contact are blocked tenant-wide'
                        example: false
                      blocked_by_users:
                        type: array
                        description: |
                          Users who have personally blocked this contact, each as a user reference.
                          Embed via `?include=blockedByUsers`.
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440006
                              readOnly: true
                            first_name:
                              type:
                                - string
                                - 'null'
                              example: Jane
                            last_name:
                              type:
                                - string
                                - 'null'
                              example: Smith
                            email:
                              type:
                                - string
                                - 'null'
                              format: email
                              example: jane.smith@example.com
                      handling_strategy:
                        type:
                          - object
                          - 'null'
                        description: |
                          Optional polymorphic redirect target applied to inbound calls from this
                          contact. `type` discriminates which `*_id` field is meaningful.
                        properties:
                          type:
                            type: string
                            enum:
                              - call_flow
                              - extension
                              - user
                              - sip_device
                            example: call_flow
                          call_flow_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          extension_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          user_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          sip_device_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/contacts/{contact}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Contacts
      summary: 'Get a Contact'
      operationId: getContact
      description: |
        Returns the contact identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Shared or personal address book entry. Phone numbers are held on the related
                  `numbers` records. `handling_strategy` carries the polymorphic redirect target
                  when inbound calls from this contact should be steered to a specific
                  destination.
                required:
                  - id
                  - pbx_id
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Contact identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  company_name:
                    type:
                      - string
                      - 'null'
                    example: 'Acme Corp'
                  department:
                    type:
                      - string
                      - 'null'
                    example: Engineering
                  job_title:
                    type:
                      - string
                      - 'null'
                    example: 'Head of Product'
                  name1:
                    type:
                      - string
                      - 'null'
                    description: 'Primary name (first name, given name)'
                    example: Jane
                  name2:
                    type:
                      - string
                      - 'null'
                    description: 'Secondary name (last name, surname)'
                    example: Smith
                  email:
                    type:
                      - string
                      - 'null'
                    format: email
                    example: jane.smith@example.com
                  notes:
                    type:
                      - string
                      - 'null'
                    example: 'Calls every Monday morning'
                  vip:
                    type: boolean
                    description: 'Whether the contact is flagged as VIP'
                    example: false
                  numbers:
                    type: array
                    description: |
                      Phone numbers attached to this contact. Embed via `?include=numbers`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440010
                          readOnly: true
                        phone_number:
                          type: string
                          description: 'The phone number (E.164 preferred)'
                          example: '+12125550100'
                        label:
                          type:
                            - string
                            - 'null'
                          description: 'Optional label for the number'
                          example: 'Direct line'
                        type:
                          type: string
                          description: 'Kind of phone number'
                          enum:
                            - business
                            - mobile
                            - other
                            - fax
                          example: business
                        speed_dial:
                          type:
                            - string
                            - 'null'
                          description: 'Optional speed-dial code for this number'
                          example: '201'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  is_private:
                    type: boolean
                    description: 'Private contacts are visible only to their `private_owner_id` user'
                    example: false
                  private_owner_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Owner user when `is_private` is true'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  editable:
                    type: boolean
                    description: |
                      Whether the **calling user** may edit this contact.
                      PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                      OMITTED entirely for PBX API-key tokens (which own all of their contacts).
                    example: true
                  is_favorite:
                    type: boolean
                    description: |
                      Whether this contact is one of the **calling user's** favourites.
                      PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                      OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                    example: false
                  groups:
                    type: array
                    description: |
                      Groups this contact belongs to. Embed via `?include=groups`.
                    items:
                      type: object
                      description: |
                        Group of users that share routing defaults and (optionally) a common caller
                        identity. Many fields are foreign keys pointing at defaults used when the
                        group's users place or receive calls.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Group identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for internal calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for external calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_outside_the_group:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension displayed to non-group members'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Default caller identity applied to the group's outbound calls"
                          example: 550e8400-e29b-41d4-a716-446655440004
                        external_uid:
                          type:
                            - string
                            - 'null'
                          description: 'External identifier from a CRM or directory sync'
                          example: grp-support
                        allow_call_pickups:
                          type: boolean
                          description: "Whether group members may pick up each others' ringing calls"
                          example: true
                        name:
                          type: string
                          maxLength: 64
                          example: 'Support team'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'First-line support'
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: "Whether the group's CIDs include the PBX-default outbound numbers"
                          example: false
                        display_tab_to_everyone_inside_voxbi:
                          type: boolean
                          description: "Whether the group's tab is shown to everyone in the PBX"
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        users:
                          type: array
                          description: |
                            Members of the group, each as a user reference. Returned only when
                            requested via `?include=users`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                  is_blocked_globally:
                    type: boolean
                    description: 'Whether inbound calls from this contact are blocked tenant-wide'
                    example: false
                  blocked_by_users:
                    type: array
                    description: |
                      Users who have personally blocked this contact, each as a user reference.
                      Embed via `?include=blockedByUsers`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440006
                          readOnly: true
                        first_name:
                          type:
                            - string
                            - 'null'
                          example: Jane
                        last_name:
                          type:
                            - string
                            - 'null'
                          example: Smith
                        email:
                          type:
                            - string
                            - 'null'
                          format: email
                          example: jane.smith@example.com
                  handling_strategy:
                    type:
                      - object
                      - 'null'
                    description: |
                      Optional polymorphic redirect target applied to inbound calls from this
                      contact. `type` discriminates which `*_id` field is meaningful.
                    properties:
                      type:
                        type: string
                        enum:
                          - call_flow
                          - extension
                          - user
                          - sip_device
                        example: call_flow
                      call_flow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      extension_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      user_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      sip_device_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - Contacts
      summary: 'Update a contact'
      operationId: updateContact
      description: |
        Update an address-book contact. Same request shape as creation, with
        `name1` still required. `is_private` is derived from `private_owner_id`
        server-side.
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Contact identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name1
              properties:
                name1:
                  type: string
                  minLength: 3
                  maxLength: 64
                name2:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 64
                email:
                  type:
                    - string
                    - 'null'
                  format: email
                  maxLength: 50
                company_name:
                  type:
                    - string
                    - 'null'
                  minLength: 2
                  maxLength: 64
                department:
                  type:
                    - string
                    - 'null'
                  minLength: 2
                  maxLength: 64
                job_title:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 32
                notes:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                private_owner_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                groups:
                  type: array
                  items:
                    type: string
                    format: uuid
                contactPhoneNumbers:
                  type: array
                  items:
                    type: object
                    required:
                      - phone_number
                      - type
                    properties:
                      phone_number:
                        type: string
                        pattern: '^\+?\d*$'
                        maxLength: 24
                      label:
                        type:
                          - string
                          - 'null'
                        maxLength: 64
                      type:
                        type: string
                      speed_dial:
                        type:
                          - string
                          - 'null'
                handling_strategy:
                  type:
                    - object
                    - 'null'
                  additionalProperties: true
            example:
              name1: Jane
              name2: Smith-Doe
              email: jane.smithdoe@example.com
              company_name: 'Acme Corp'
              contactPhoneNumbers:
                -
                  phone_number: '+12125550101'
                  label: Work
                  type: work
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Shared or personal address book entry. Phone numbers are held on the related
                      `numbers` records. `handling_strategy` carries the polymorphic redirect target
                      when inbound calls from this contact should be steered to a specific
                      destination.
                    required:
                      - id
                      - pbx_id
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Contact identifier'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Pbx identifier (tenant)'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      company_name:
                        type:
                          - string
                          - 'null'
                        example: 'Acme Corp'
                      department:
                        type:
                          - string
                          - 'null'
                        example: Engineering
                      job_title:
                        type:
                          - string
                          - 'null'
                        example: 'Head of Product'
                      name1:
                        type:
                          - string
                          - 'null'
                        description: 'Primary name (first name, given name)'
                        example: Jane
                      name2:
                        type:
                          - string
                          - 'null'
                        description: 'Secondary name (last name, surname)'
                        example: Smith
                      email:
                        type:
                          - string
                          - 'null'
                        format: email
                        example: jane.smith@example.com
                      notes:
                        type:
                          - string
                          - 'null'
                        example: 'Calls every Monday morning'
                      vip:
                        type: boolean
                        description: 'Whether the contact is flagged as VIP'
                        example: false
                      numbers:
                        type: array
                        description: |
                          Phone numbers attached to this contact. Embed via `?include=numbers`.
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440010
                              readOnly: true
                            phone_number:
                              type: string
                              description: 'The phone number (E.164 preferred)'
                              example: '+12125550100'
                            label:
                              type:
                                - string
                                - 'null'
                              description: 'Optional label for the number'
                              example: 'Direct line'
                            type:
                              type: string
                              description: 'Kind of phone number'
                              enum:
                                - business
                                - mobile
                                - other
                                - fax
                              example: business
                            speed_dial:
                              type:
                                - string
                                - 'null'
                              description: 'Optional speed-dial code for this number'
                              example: '201'
                            created_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            updated_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                      is_private:
                        type: boolean
                        description: 'Private contacts are visible only to their `private_owner_id` user'
                        example: false
                      private_owner_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Owner user when `is_private` is true'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      editable:
                        type: boolean
                        description: |
                          Whether the **calling user** may edit this contact.
                          PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                          OMITTED entirely for PBX API-key tokens (which own all of their contacts).
                        example: true
                      is_favorite:
                        type: boolean
                        description: |
                          Whether this contact is one of the **calling user's** favourites.
                          PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                          OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                        example: false
                      groups:
                        type: array
                        description: |
                          Groups this contact belongs to. Embed via `?include=groups`.
                        items:
                          type: object
                          description: |
                            Group of users that share routing defaults and (optionally) a common caller
                            identity. Many fields are foreign keys pointing at defaults used when the
                            group's users place or receive calls.
                          required:
                            - id
                            - pbx_id
                            - name
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Group identifier'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Pbx identifier (tenant)'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            default_internal_call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Call flow used for internal calls reaching this group'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            default_external_call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Call flow used for external calls reaching this group'
                              example: 550e8400-e29b-41d4-a716-446655440003
                            extension_id_shown_outside_the_group:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: 'Extension displayed to non-group members'
                              example: 550e8400-e29b-41d4-a716-446655440005
                            default_caller_identity_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: "Default caller identity applied to the group's outbound calls"
                              example: 550e8400-e29b-41d4-a716-446655440004
                            external_uid:
                              type:
                                - string
                                - 'null'
                              description: 'External identifier from a CRM or directory sync'
                              example: grp-support
                            allow_call_pickups:
                              type: boolean
                              description: "Whether group members may pick up each others' ringing calls"
                              example: true
                            name:
                              type: string
                              maxLength: 64
                              example: 'Support team'
                            description:
                              type:
                                - string
                                - 'null'
                              maxLength: 255
                              example: 'First-line support'
                            allow_default_pbxes_outgoing_phone_numbers:
                              type: boolean
                              description: "Whether the group's CIDs include the PBX-default outbound numbers"
                              example: false
                            display_tab_to_everyone_inside_voxbi:
                              type: boolean
                              description: "Whether the group's tab is shown to everyone in the PBX"
                              example: false
                            created_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            updated_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            users:
                              type: array
                              description: |
                                Members of the group, each as a user reference. Returned only when
                                requested via `?include=users`.
                              items:
                                type: object
                                properties:
                                  id:
                                    type: string
                                    format: uuid
                                    example: 550e8400-e29b-41d4-a716-446655440006
                                    readOnly: true
                                  first_name:
                                    type:
                                      - string
                                      - 'null'
                                    example: Jane
                                  last_name:
                                    type:
                                      - string
                                      - 'null'
                                    example: Smith
                                  email:
                                    type:
                                      - string
                                      - 'null'
                                    format: email
                                    example: jane.smith@example.com
                      is_blocked_globally:
                        type: boolean
                        description: 'Whether inbound calls from this contact are blocked tenant-wide'
                        example: false
                      blocked_by_users:
                        type: array
                        description: |
                          Users who have personally blocked this contact, each as a user reference.
                          Embed via `?include=blockedByUsers`.
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440006
                              readOnly: true
                            first_name:
                              type:
                                - string
                                - 'null'
                              example: Jane
                            last_name:
                              type:
                                - string
                                - 'null'
                              example: Smith
                            email:
                              type:
                                - string
                                - 'null'
                              format: email
                              example: jane.smith@example.com
                      handling_strategy:
                        type:
                          - object
                          - 'null'
                        description: |
                          Optional polymorphic redirect target applied to inbound calls from this
                          contact. `type` discriminates which `*_id` field is meaningful.
                        properties:
                          type:
                            type: string
                            enum:
                              - call_flow
                              - extension
                              - user
                              - sip_device
                            example: call_flow
                          call_flow_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          extension_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          user_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          sip_device_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Contacts
      summary: 'Delete a contact'
      operationId: deleteContact
      description: 'Soft-delete a contact. The contact is removed from list responses but can be restored by an administrator.'
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Contact identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/contacts/{id}/block':
    post:
      tags:
        - Contacts
      summary: 'Block a contact'
      operationId: postContactBlock
      description: |
        Triggers the action on the targeted contact block.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          description: 'Contact ID'
          required: true
          schema:
            type: integer
            example: 1
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: success
                message: 'Contact blocked.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/contacts/{id}/unblock':
    post:
      tags:
        - Contacts
      summary: 'Unblock a contact'
      operationId: postContactUnblock
      description: |
        Triggers the action on the targeted contact unblock.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          description: 'Contact ID'
          required: true
          schema:
            type: integer
            example: 1
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: success
                message: 'Contact unblocked.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /contacts/favorite:
    post:
      tags:
        - Contacts
      summary: 'Toggle a contact as favorite'
      operationId: postContactFavorite
      description: |
        Creates a new contact favorite. Validation rules and required fields are defined in the
        request body schema below.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - contact_id
              properties:
                contact_id:
                  type: integer
                  description: 'ID of the contact to toggle as favorite'
                  example: 1
            example:
              contact_id: 1
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  is_favorite:
                    type: boolean
              example:
                status: success
                is_favorite: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/source/{source}/contacts':
    get:
      tags:
        - Contacts
      summary: 'Get contacts from a specific source'
      operationId: getContactSourceContacts
      description: |
        Returns the contact source contacts identified by the path parameter. Multi-tenant scoping
        is enforced: the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: source
          in: path
          description: 'Source identifier'
          required: true
          schema:
            type: string
            example: google
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Shared or personal address book entry. Phone numbers are held on the related
                        `numbers` records. `handling_strategy` carries the polymorphic redirect target
                        when inbound calls from this contact should be steered to a specific
                        destination.
                      required:
                        - id
                        - pbx_id
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Contact identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        company_name:
                          type:
                            - string
                            - 'null'
                          example: 'Acme Corp'
                        department:
                          type:
                            - string
                            - 'null'
                          example: Engineering
                        job_title:
                          type:
                            - string
                            - 'null'
                          example: 'Head of Product'
                        name1:
                          type:
                            - string
                            - 'null'
                          description: 'Primary name (first name, given name)'
                          example: Jane
                        name2:
                          type:
                            - string
                            - 'null'
                          description: 'Secondary name (last name, surname)'
                          example: Smith
                        email:
                          type:
                            - string
                            - 'null'
                          format: email
                          example: jane.smith@example.com
                        notes:
                          type:
                            - string
                            - 'null'
                          example: 'Calls every Monday morning'
                        vip:
                          type: boolean
                          description: 'Whether the contact is flagged as VIP'
                          example: false
                        numbers:
                          type: array
                          description: |
                            Phone numbers attached to this contact. Embed via `?include=numbers`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440010
                                readOnly: true
                              phone_number:
                                type: string
                                description: 'The phone number (E.164 preferred)'
                                example: '+12125550100'
                              label:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional label for the number'
                                example: 'Direct line'
                              type:
                                type: string
                                description: 'Kind of phone number'
                                enum:
                                  - business
                                  - mobile
                                  - other
                                  - fax
                                example: business
                              speed_dial:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional speed-dial code for this number'
                                example: '201'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        is_private:
                          type: boolean
                          description: 'Private contacts are visible only to their `private_owner_id` user'
                          example: false
                        private_owner_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Owner user when `is_private` is true'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        editable:
                          type: boolean
                          description: |
                            Whether the **calling user** may edit this contact.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (which own all of their contacts).
                          example: true
                        is_favorite:
                          type: boolean
                          description: |
                            Whether this contact is one of the **calling user's** favourites.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                          example: false
                        groups:
                          type: array
                          description: |
                            Groups this contact belongs to. Embed via `?include=groups`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        is_blocked_globally:
                          type: boolean
                          description: 'Whether inbound calls from this contact are blocked tenant-wide'
                          example: false
                        blocked_by_users:
                          type: array
                          description: |
                            Users who have personally blocked this contact, each as a user reference.
                            Embed via `?include=blockedByUsers`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                        handling_strategy:
                          type:
                            - object
                            - 'null'
                          description: |
                            Optional polymorphic redirect target applied to inbound calls from this
                            contact. `type` discriminates which `*_id` field is meaningful.
                          properties:
                            type:
                              type: string
                              enum:
                                - call_flow
                                - extension
                                - user
                                - sip_device
                              example: call_flow
                            call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            extension_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            user_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            sip_device_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    company_name: 'Acme Corp'
                    department: Engineering
                    job_title: 'Head of Product'
                    name1: Jane
                    name2: Smith
                    email: jane.smith@example.com
                    notes: 'Calls every Monday morning'
                    is_private: false
                    is_blocked_globally: false
                    private_owner_id: 550e8400-e29b-41d4-a716-446655440002
                    handling_strategy:
                      type: call_flow
                      call_flow_id: 550e8400-e29b-41d4-a716-446655440000
                      extension_id: 550e8400-e29b-41d4-a716-446655440000
                      user_id: 550e8400-e29b-41d4-a716-446655440000
                      sip_device_id: 550e8400-e29b-41d4-a716-446655440000
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /contacts/imports:
    get:
      tags:
        - ContactImports
      summary: 'List your contact imports (user)'
      operationId: listContactImports
      description: |
        Returns a paginated list of the authenticated user's contact imports, newest
        first. This endpoint accepts a USER token only (not a PBX API key): a user
        only ever sees their own imports.

        Use `filter[status]=incomplete` to narrow by lifecycle stage, and
        `?include=records,errors` to embed row-level detail.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          description: |
            Sort field. Prefix with `-` for descending. Allowed: `created_at`,
            `completed_at`, `status`. Defaults to `-created_at`.
          in: query
          required: false
          schema:
            type: string
          example: '-created_at'
        -
          name: 'filter[status]'
          description: 'Filter by exact lifecycle status (e.g. `incomplete`, `completed`).'
          in: query
          required: false
          schema:
            type: string
          example: incomplete
        -
          name: include
          description: 'Comma-separated related detail to embed. Allowed: `records`, `errors`.'
          in: query
          required: false
          schema:
            type: string
          example: 'records,errors'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        An API-driven contact import. Every import is strictly owner-scoped: a user
                        only ever sees and drives their own imports, and every contact it creates is
                        private to that user. The import moves through a small state machine:
                        `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                        `completed` / `completed_with_errors` / `failed`.

                        `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                        otherwise.
                      required:
                        - id
                        - status
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Import identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        status:
                          type: string
                          description: 'Current stage of the import lifecycle'
                          enum:
                            - incomplete
                            - pending
                            - processing
                            - completed
                            - completed_with_errors
                            - failed
                          example: incomplete
                        file_type:
                          type:
                            - string
                            - 'null'
                          description: 'Detected type of the uploaded file'
                          enum:
                            - csv
                            - xls
                            - xlsx
                            - null
                          example: csv
                        records_count:
                          type: integer
                          description: 'Number of contacts imported (populated once processed)'
                          example: 42
                        errors_count:
                          type: integer
                          description: 'Number of rows that failed to import'
                          example: 3
                        can_confirm:
                          type: boolean
                          description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                          example: true
                        header_row_position:
                          type:
                            - integer
                            - 'null'
                          description: '1-based row holding the column headers.'
                          example: 1
                        sheet_index:
                          type:
                            - integer
                            - 'null'
                          description: '0-based sheet to read (Excel files).'
                          example: null
                        delimiter:
                          type:
                            - string
                            - 'null'
                          description: 'CSV field delimiter (auto-detected when null).'
                          example: null
                        enclosure:
                          type:
                            - string
                            - 'null'
                          description: 'CSV field enclosure character.'
                          example: '"'
                        input_encoding:
                          type:
                            - string
                            - 'null'
                          description: 'Character encoding of the file.'
                          example: UTF-8
                        skip_on_error:
                          type: boolean
                          description: 'When true, invalid rows are skipped instead of failing the import.'
                          example: true
                        notify_owner_by_email:
                          type: boolean
                          description: 'Whether the owner is emailed once the import finishes.'
                          example: false
                        webhook_url:
                          type:
                            - string
                            - 'null'
                          format: uri
                          description: 'Client webhook that receives lifecycle events.'
                          example: null
                        mappings:
                          type: array
                          description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                          items:
                            type: object
                            properties:
                              field:
                                type: string
                                example: name1
                              column:
                                type: integer
                                example: 0
                              subfields:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    name:
                                      type: string
                                      example: type
                                    value:
                                      type: string
                                      example: mobile
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2026-01-15T09:30:00Z'
                          readOnly: true
                        started_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When background processing began'
                          example: '2026-01-15T09:31:00Z'
                          readOnly: true
                        completed_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When background processing finished'
                          example: '2026-01-15T09:31:45Z'
                          readOnly: true
                        records:
                          type: array
                          description: 'Imported contacts. Only present when requested via `?include=records`.'
                          items:
                            type: object
                            properties:
                              model_id:
                                type: string
                                format: uuid
                                description: 'Id of the created / updated contact'
                                example: 550e8400-e29b-41d4-a716-446655440010
                              is_new:
                                type: boolean
                                description: 'True when a new contact was created, false when an existing one was updated'
                                example: true
                              was_trashed:
                                type: boolean
                                description: 'True when a soft-deleted contact was restored by the import'
                                example: false
                        errors:
                          type: array
                          description: 'Row-level failures. Only present when requested via `?include=errors`.'
                          items:
                            type: object
                            properties:
                              row:
                                type: integer
                                description: '1-based row number in the uploaded file'
                                example: 7
                              attribute:
                                type:
                                  - string
                                  - 'null'
                                description: 'The field that failed validation, when applicable'
                                example: email
                              messages:
                                type: array
                                items:
                                  type: string
                                example:
                                  - 'The email must be a valid email address.'
                              row_data:
                                type: object
                                additionalProperties: true
                                description: 'The offending row as read from the file'
                                example:
                                  name1: Jane
                                  email: not-an-email
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
    post:
      tags:
        - ContactImports
      summary: 'Upload a contact import file (user)'
      operationId: createContactImport
      description: |
        Uploads a CSV or Excel file and creates an import in the `incomplete` state.
        The file is only stored at this step: no contacts are created yet. Next,
        configure parsing via the settings endpoint, map columns via the mapping
        endpoints, then confirm.

        Accepts a USER token only. The created import (and every contact it will
        create) is private to the authenticated user. Send the file as
        `multipart/form-data` under the `file` key. Accepted types: CSV, XLS, XLSX.

        Rate limited: at most one import may be created per minute per user. Only
        successful creates count, so a rejected request (422) never blocks a valid
        retry. Configuring an existing import is not limited.

        Notification preferences may be set here or via the settings endpoint.
      security:
        -
          bearerAuth: {}
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: 'The CSV or Excel file to import (max size configured server-side).'
                notify_owner_by_email:
                  type: boolean
                  description: 'Email you once the import finishes (completed or failed).'
                  default: false
                webhook_url:
                  type:
                    - string
                    - 'null'
                  format: uri
                  description: 'Public https URL. Import lifecycle events (pending, processing, completed, completed_with_errors, failed) are POSTed here as JSON, signed with an X-Voxbi-Signature (HMAC-SHA256) header. Typically used to drive live in-app notifications: point it at your backend, which relays each event to the signed-in user over your realtime channel (no polling). Any query params in the URL are echoed back on every delivery, so you can route the notification. Private, loopback and non-https URLs are rejected.'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: |
            Created. The response is the import resource itself (unwrapped, not under
            a `data` key). Fetch the detected columns next via the mapping-options
            endpoint.
          content:
            application/json:
              schema:
                type: object
                description: |
                  An API-driven contact import. Every import is strictly owner-scoped: a user
                  only ever sees and drives their own imports, and every contact it creates is
                  private to that user. The import moves through a small state machine:
                  `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                  `completed` / `completed_with_errors` / `failed`.

                  `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                  otherwise.
                required:
                  - id
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Import identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  status:
                    type: string
                    description: 'Current stage of the import lifecycle'
                    enum:
                      - incomplete
                      - pending
                      - processing
                      - completed
                      - completed_with_errors
                      - failed
                    example: incomplete
                  file_type:
                    type:
                      - string
                      - 'null'
                    description: 'Detected type of the uploaded file'
                    enum:
                      - csv
                      - xls
                      - xlsx
                      - null
                    example: csv
                  records_count:
                    type: integer
                    description: 'Number of contacts imported (populated once processed)'
                    example: 42
                  errors_count:
                    type: integer
                    description: 'Number of rows that failed to import'
                    example: 3
                  can_confirm:
                    type: boolean
                    description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                    example: true
                  header_row_position:
                    type:
                      - integer
                      - 'null'
                    description: '1-based row holding the column headers.'
                    example: 1
                  sheet_index:
                    type:
                      - integer
                      - 'null'
                    description: '0-based sheet to read (Excel files).'
                    example: null
                  delimiter:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field delimiter (auto-detected when null).'
                    example: null
                  enclosure:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field enclosure character.'
                    example: '"'
                  input_encoding:
                    type:
                      - string
                      - 'null'
                    description: 'Character encoding of the file.'
                    example: UTF-8
                  skip_on_error:
                    type: boolean
                    description: 'When true, invalid rows are skipped instead of failing the import.'
                    example: true
                  notify_owner_by_email:
                    type: boolean
                    description: 'Whether the owner is emailed once the import finishes.'
                    example: false
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    format: uri
                    description: 'Client webhook that receives lifecycle events.'
                    example: null
                  mappings:
                    type: array
                    description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        column:
                          type: integer
                          example: 0
                        subfields:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              value:
                                type: string
                                example: mobile
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-01-15T09:30:00Z'
                    readOnly: true
                  started_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing began'
                    example: '2026-01-15T09:31:00Z'
                    readOnly: true
                  completed_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing finished'
                    example: '2026-01-15T09:31:45Z'
                    readOnly: true
                  records:
                    type: array
                    description: 'Imported contacts. Only present when requested via `?include=records`.'
                    items:
                      type: object
                      properties:
                        model_id:
                          type: string
                          format: uuid
                          description: 'Id of the created / updated contact'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        is_new:
                          type: boolean
                          description: 'True when a new contact was created, false when an existing one was updated'
                          example: true
                        was_trashed:
                          type: boolean
                          description: 'True when a soft-deleted contact was restored by the import'
                          example: false
                  errors:
                    type: array
                    description: 'Row-level failures. Only present when requested via `?include=errors`.'
                    items:
                      type: object
                      properties:
                        row:
                          type: integer
                          description: '1-based row number in the uploaded file'
                          example: 7
                        attribute:
                          type:
                            - string
                            - 'null'
                          description: 'The field that failed validation, when applicable'
                          example: email
                        messages:
                          type: array
                          items:
                            type: string
                          example:
                            - 'The email must be a valid email address.'
                        row_data:
                          type: object
                          additionalProperties: true
                          description: 'The offending row as read from the file'
                          example:
                            name1: Jane
                            email: not-an-email
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
  /contacts/imports/sample:
    get:
      tags:
        - ContactImports
      summary: 'Download a sample import file (user)'
      operationId: getContactImportSample
      description: |
        Downloads a headers-only sample CSV showing the contact fields the import
        accepts (the same file the Cockpit import wizard offers). Column headers are
        illustrative only: the import mapping is free-form, so you map your own
        file's columns onto the target fields regardless of their headers.
      security:
        -
          bearerAuth: {}
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. A CSV file download.'
          content:
            text/csv:
              schema:
                type: string
                format: binary
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  '/contacts/imports/{id}':
    get:
      tags:
        - ContactImports
      summary: 'Get one of your contact imports (user)'
      operationId: getContactImport
      description: |
        Returns a single import owned by the authenticated user. Use
        `?include=records,errors` to embed the imported contacts and any row-level
        failures. Accepts a USER token only; another user's import returns 404.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
        -
          name: include
          description: 'Comma-separated related detail to embed. Allowed: `records`, `errors`.'
          in: query
          required: false
          schema:
            type: string
          example: 'records,errors'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. The import resource itself (unwrapped, not under a `data` key).'
          content:
            application/json:
              schema:
                type: object
                description: |
                  An API-driven contact import. Every import is strictly owner-scoped: a user
                  only ever sees and drives their own imports, and every contact it creates is
                  private to that user. The import moves through a small state machine:
                  `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                  `completed` / `completed_with_errors` / `failed`.

                  `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                  otherwise.
                required:
                  - id
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Import identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  status:
                    type: string
                    description: 'Current stage of the import lifecycle'
                    enum:
                      - incomplete
                      - pending
                      - processing
                      - completed
                      - completed_with_errors
                      - failed
                    example: incomplete
                  file_type:
                    type:
                      - string
                      - 'null'
                    description: 'Detected type of the uploaded file'
                    enum:
                      - csv
                      - xls
                      - xlsx
                      - null
                    example: csv
                  records_count:
                    type: integer
                    description: 'Number of contacts imported (populated once processed)'
                    example: 42
                  errors_count:
                    type: integer
                    description: 'Number of rows that failed to import'
                    example: 3
                  can_confirm:
                    type: boolean
                    description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                    example: true
                  header_row_position:
                    type:
                      - integer
                      - 'null'
                    description: '1-based row holding the column headers.'
                    example: 1
                  sheet_index:
                    type:
                      - integer
                      - 'null'
                    description: '0-based sheet to read (Excel files).'
                    example: null
                  delimiter:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field delimiter (auto-detected when null).'
                    example: null
                  enclosure:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field enclosure character.'
                    example: '"'
                  input_encoding:
                    type:
                      - string
                      - 'null'
                    description: 'Character encoding of the file.'
                    example: UTF-8
                  skip_on_error:
                    type: boolean
                    description: 'When true, invalid rows are skipped instead of failing the import.'
                    example: true
                  notify_owner_by_email:
                    type: boolean
                    description: 'Whether the owner is emailed once the import finishes.'
                    example: false
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    format: uri
                    description: 'Client webhook that receives lifecycle events.'
                    example: null
                  mappings:
                    type: array
                    description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        column:
                          type: integer
                          example: 0
                        subfields:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              value:
                                type: string
                                example: mobile
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-01-15T09:30:00Z'
                    readOnly: true
                  started_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing began'
                    example: '2026-01-15T09:31:00Z'
                    readOnly: true
                  completed_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing finished'
                    example: '2026-01-15T09:31:45Z'
                    readOnly: true
                  records:
                    type: array
                    description: 'Imported contacts. Only present when requested via `?include=records`.'
                    items:
                      type: object
                      properties:
                        model_id:
                          type: string
                          format: uuid
                          description: 'Id of the created / updated contact'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        is_new:
                          type: boolean
                          description: 'True when a new contact was created, false when an existing one was updated'
                          example: true
                        was_trashed:
                          type: boolean
                          description: 'True when a soft-deleted contact was restored by the import'
                          example: false
                  errors:
                    type: array
                    description: 'Row-level failures. Only present when requested via `?include=errors`.'
                    items:
                      type: object
                      properties:
                        row:
                          type: integer
                          description: '1-based row number in the uploaded file'
                          example: 7
                        attribute:
                          type:
                            - string
                            - 'null'
                          description: 'The field that failed validation, when applicable'
                          example: email
                        messages:
                          type: array
                          items:
                            type: string
                          example:
                            - 'The email must be a valid email address.'
                        row_data:
                          type: object
                          additionalProperties: true
                          description: 'The offending row as read from the file'
                          example:
                            name1: Jane
                            email: not-an-email
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    delete:
      tags:
        - ContactImports
      summary: 'Delete one of your contact imports (user)'
      operationId: deleteContactImport
      description: |
        Permanently deletes one of the authenticated user's imports, along with its
        row-level records, errors, and the stored source file. An import in any
        status may be deleted; the contacts it already created are NOT removed.
        Accepts a USER token only; another user's import returns 404.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'No Content'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/contacts/imports/{id}/settings':
    get:
      tags:
        - ContactImports
      summary: 'Get parsing settings for an import (user)'
      operationId: getContactImportSettings
      description: |
        Returns the parsing settings that apply to this import's file type, each with
        its type, default, and current value. The client renders exactly these; CSV
        imports expose `delimiter`, `enclosure`, and `input_encoding`, while Excel
        imports expose `sheet_index`. Only an `incomplete` import can be read here
        (otherwise 409).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    key:
                      type: string
                      example: input_encoding
                    type:
                      type: string
                      enum:
                        - integer
                        - boolean
                        - string
                      example: string
                    default:
                      description: 'Default value (type depends on `type`); may be null.'
                      example: UTF-8
                    current:
                      description: 'Currently stored value; may be null.'
                      example: null
                    allowed_values:
                      type: array
                      description: 'Present only for settings with a fixed value set (e.g. `input_encoding`).'
                      items:
                        type: string
                      example:
                        - UTF-8
                        - ISO-8859-1
              example:
                -
                  key: header_row_position
                  type: integer
                  default: 1
                  current: 1
                -
                  key: skip_on_error
                  type: boolean
                  default: true
                  current: true
                -
                  key: delimiter
                  type: string
                  default: null
                  current: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: |
            Conflict. The import is no longer in a state that allows this action (for
            example, it has already been submitted for processing). Only an `incomplete`
            import can be configured or confirmed.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: Conflict
                properties:
                  message:
                    type: string
              example:
                message: 'This import has already been submitted.'
    put:
      tags:
        - ContactImports
      summary: 'Update parsing settings for an import (user)'
      operationId: updateContactImportSettings
      description: |
        Updates the parsing settings for an `incomplete` import. Send only the keys
        you want to change. Only an `incomplete` import can be updated (otherwise
        409).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                header_row_position:
                  type:
                    - integer
                    - 'null'
                  minimum: 1
                  description: '1-based row that holds the column headers.'
                sheet_index:
                  type:
                    - integer
                    - 'null'
                  minimum: 0
                  description: '0-based sheet to read (Excel files).'
                delimiter:
                  type:
                    - string
                    - 'null'
                  maxLength: 5
                  description: 'CSV field delimiter.'
                enclosure:
                  type:
                    - string
                    - 'null'
                  maxLength: 5
                  description: 'CSV field enclosure character.'
                input_encoding:
                  type:
                    - string
                    - 'null'
                  maxLength: 50
                  description: 'Character encoding of the file; must be a supported encoding.'
                skip_on_error:
                  type: boolean
                  description: 'When true, invalid rows are skipped instead of failing the import.'
                notify_owner_by_email:
                  type: boolean
                  description: 'Email you once the import finishes (completed or failed).'
                webhook_url:
                  type:
                    - string
                    - 'null'
                  format: uri
                  description: 'Public https URL. Import lifecycle events are POSTed here as JSON, signed with an X-Voxbi-Signature (HMAC-SHA256) header. Typically used to drive live in-app notifications: relay each event to the signed-in user over your realtime channel (no polling); query params in the URL are echoed back so you can route it. Private, loopback and non-https URLs are rejected. Send null to clear.'
            example:
              header_row_position: 1
              delimiter: ','
              input_encoding: UTF-8
              skip_on_error: true
              notify_owner_by_email: true
              webhook_url: 'https://hooks.example.com/imports'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: |
            OK. The updated import resource (unwrapped). It carries the setting
            values just set (header_row_position, notify_owner_by_email, ...).
          content:
            application/json:
              schema:
                type: object
                description: |
                  An API-driven contact import. Every import is strictly owner-scoped: a user
                  only ever sees and drives their own imports, and every contact it creates is
                  private to that user. The import moves through a small state machine:
                  `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                  `completed` / `completed_with_errors` / `failed`.

                  `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                  otherwise.
                required:
                  - id
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Import identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  status:
                    type: string
                    description: 'Current stage of the import lifecycle'
                    enum:
                      - incomplete
                      - pending
                      - processing
                      - completed
                      - completed_with_errors
                      - failed
                    example: incomplete
                  file_type:
                    type:
                      - string
                      - 'null'
                    description: 'Detected type of the uploaded file'
                    enum:
                      - csv
                      - xls
                      - xlsx
                      - null
                    example: csv
                  records_count:
                    type: integer
                    description: 'Number of contacts imported (populated once processed)'
                    example: 42
                  errors_count:
                    type: integer
                    description: 'Number of rows that failed to import'
                    example: 3
                  can_confirm:
                    type: boolean
                    description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                    example: true
                  header_row_position:
                    type:
                      - integer
                      - 'null'
                    description: '1-based row holding the column headers.'
                    example: 1
                  sheet_index:
                    type:
                      - integer
                      - 'null'
                    description: '0-based sheet to read (Excel files).'
                    example: null
                  delimiter:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field delimiter (auto-detected when null).'
                    example: null
                  enclosure:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field enclosure character.'
                    example: '"'
                  input_encoding:
                    type:
                      - string
                      - 'null'
                    description: 'Character encoding of the file.'
                    example: UTF-8
                  skip_on_error:
                    type: boolean
                    description: 'When true, invalid rows are skipped instead of failing the import.'
                    example: true
                  notify_owner_by_email:
                    type: boolean
                    description: 'Whether the owner is emailed once the import finishes.'
                    example: false
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    format: uri
                    description: 'Client webhook that receives lifecycle events.'
                    example: null
                  mappings:
                    type: array
                    description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        column:
                          type: integer
                          example: 0
                        subfields:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              value:
                                type: string
                                example: mobile
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-01-15T09:30:00Z'
                    readOnly: true
                  started_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing began'
                    example: '2026-01-15T09:31:00Z'
                    readOnly: true
                  completed_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing finished'
                    example: '2026-01-15T09:31:45Z'
                    readOnly: true
                  records:
                    type: array
                    description: 'Imported contacts. Only present when requested via `?include=records`.'
                    items:
                      type: object
                      properties:
                        model_id:
                          type: string
                          format: uuid
                          description: 'Id of the created / updated contact'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        is_new:
                          type: boolean
                          description: 'True when a new contact was created, false when an existing one was updated'
                          example: true
                        was_trashed:
                          type: boolean
                          description: 'True when a soft-deleted contact was restored by the import'
                          example: false
                  errors:
                    type: array
                    description: 'Row-level failures. Only present when requested via `?include=errors`.'
                    items:
                      type: object
                      properties:
                        row:
                          type: integer
                          description: '1-based row number in the uploaded file'
                          example: 7
                        attribute:
                          type:
                            - string
                            - 'null'
                          description: 'The field that failed validation, when applicable'
                          example: email
                        messages:
                          type: array
                          items:
                            type: string
                          example:
                            - 'The email must be a valid email address.'
                        row_data:
                          type: object
                          additionalProperties: true
                          description: 'The offending row as read from the file'
                          example:
                            name1: Jane
                            email: not-an-email
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: |
            Conflict. The import is no longer in a state that allows this action (for
            example, it has already been submitted for processing). Only an `incomplete`
            import can be configured or confirmed.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: Conflict
                properties:
                  message:
                    type: string
              example:
                message: 'This import has already been submitted.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/contacts/imports/{id}/mapping-options':
    get:
      tags:
        - ContactImports
      summary: 'Get column mapping options for an import (user)'
      operationId: getContactImportMappingOptions
      description: |
        Returns everything the client needs to render the mapping step: the detected
        file columns (each with a stable `id` used as `column` in the mapping
        payload) and the allow-listed target fields a column may be mapped to. Only
        these target fields are accepted when saving a mapping: no other model
        attribute (e.g. `private_owner_id`, `pbx_id`, groups) can be targeted, and
        nothing is auto-mapped. Only an `incomplete` import can be read here
        (otherwise 409).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  file_columns:
                    type: array
                    description: 'Detected columns from the uploaded file.'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          description: 'Stable column id (used as `column` in the mapping payload).'
                          example: 0
                        name:
                          type: string
                          description: 'The column header text.'
                          example: 'First name'
                  target_fields:
                    type: array
                    description: 'The only contact fields a column may be mapped to.'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        label:
                          type: string
                          example: 'First name'
                        type:
                          type: string
                          enum:
                            - text
                            - relationship
                          example: text
                        multiple:
                          type: boolean
                          description: 'Present (true) only on fields that accept several columns.'
                          example: true
                        subfields:
                          type: array
                          description: 'Extra values a mapping to this field must carry (e.g. a phone `type`).'
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              type:
                                type: string
                                example: enum
                              options:
                                type: array
                                items:
                                  type: string
                                example:
                                  - business
                                  - mobile
                                  - other
                                  - fax
              example:
                file_columns:
                  -
                    id: 0
                    name: 'First name'
                  -
                    id: 1
                    name: 'Last name'
                  -
                    id: 2
                    name: Mobile
                target_fields:
                  -
                    field: name1
                    label: 'First name'
                    type: text
                  -
                    field: contactPhoneNumbers
                    label: 'Phone numbers'
                    type: relationship
                    multiple: true
                    subfields:
                      -
                        name: type
                        type: enum
                        options:
                          - business
                          - mobile
                          - other
                          - fax
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: |
            Conflict. The import is no longer in a state that allows this action (for
            example, it has already been submitted for processing). Only an `incomplete`
            import can be configured or confirmed.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: Conflict
                properties:
                  message:
                    type: string
              example:
                message: 'This import has already been submitted.'
  '/contacts/imports/{id}/mappings':
    put:
      tags:
        - ContactImports
      summary: 'Save the column mapping for an import (user)'
      operationId: updateContactImportMappings
      description: |
        Saves how the file's columns map onto contact fields. Each entry maps one
        column (`column` = a `file_columns[].id` from mapping-options) onto one
        `field`. `field` must be one of the allow-listed target fields; any other
        value (including `private_owner_id`, `pbx_id`, `is_private`, or a groups
        column) is rejected with 422, so a client cannot forge a mapping to assign
        contacts to another user or tenant. A `contactPhoneNumbers` mapping must
        carry a `type` sub-field. A single-value field may be mapped to at most one
        column; only fields flagged `multiple: true` (currently
        `contactPhoneNumbers`) may take several columns, otherwise a duplicate
        mapping is rejected with 422. Only an `incomplete` import can be mapped
        (otherwise 409).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - mappings
              properties:
                mappings:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - field
                      - column
                    properties:
                      field:
                        type: string
                        description: 'An allow-listed target field (see mapping-options.target_fields).'
                        example: name1
                      column:
                        type: integer
                        minimum: 0
                        description: 'A file column id from mapping-options.file_columns.'
                        example: 0
                      subfields:
                        type: array
                        description: 'Sub-field values required by the target field (e.g. a phone `type`).'
                        items:
                          type: object
                          required:
                            - name
                            - value
                          properties:
                            name:
                              type: string
                              example: type
                            value:
                              type: string
                              example: mobile
            example:
              mappings:
                -
                  field: name1
                  column: 0
                -
                  field: name2
                  column: 1
                -
                  field: contactPhoneNumbers
                  column: 2
                  subfields:
                    -
                      name: type
                      value: mobile
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. The updated import resource (unwrapped).'
          content:
            application/json:
              schema:
                type: object
                description: |
                  An API-driven contact import. Every import is strictly owner-scoped: a user
                  only ever sees and drives their own imports, and every contact it creates is
                  private to that user. The import moves through a small state machine:
                  `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                  `completed` / `completed_with_errors` / `failed`.

                  `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                  otherwise.
                required:
                  - id
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Import identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  status:
                    type: string
                    description: 'Current stage of the import lifecycle'
                    enum:
                      - incomplete
                      - pending
                      - processing
                      - completed
                      - completed_with_errors
                      - failed
                    example: incomplete
                  file_type:
                    type:
                      - string
                      - 'null'
                    description: 'Detected type of the uploaded file'
                    enum:
                      - csv
                      - xls
                      - xlsx
                      - null
                    example: csv
                  records_count:
                    type: integer
                    description: 'Number of contacts imported (populated once processed)'
                    example: 42
                  errors_count:
                    type: integer
                    description: 'Number of rows that failed to import'
                    example: 3
                  can_confirm:
                    type: boolean
                    description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                    example: true
                  header_row_position:
                    type:
                      - integer
                      - 'null'
                    description: '1-based row holding the column headers.'
                    example: 1
                  sheet_index:
                    type:
                      - integer
                      - 'null'
                    description: '0-based sheet to read (Excel files).'
                    example: null
                  delimiter:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field delimiter (auto-detected when null).'
                    example: null
                  enclosure:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field enclosure character.'
                    example: '"'
                  input_encoding:
                    type:
                      - string
                      - 'null'
                    description: 'Character encoding of the file.'
                    example: UTF-8
                  skip_on_error:
                    type: boolean
                    description: 'When true, invalid rows are skipped instead of failing the import.'
                    example: true
                  notify_owner_by_email:
                    type: boolean
                    description: 'Whether the owner is emailed once the import finishes.'
                    example: false
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    format: uri
                    description: 'Client webhook that receives lifecycle events.'
                    example: null
                  mappings:
                    type: array
                    description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        column:
                          type: integer
                          example: 0
                        subfields:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              value:
                                type: string
                                example: mobile
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-01-15T09:30:00Z'
                    readOnly: true
                  started_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing began'
                    example: '2026-01-15T09:31:00Z'
                    readOnly: true
                  completed_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing finished'
                    example: '2026-01-15T09:31:45Z'
                    readOnly: true
                  records:
                    type: array
                    description: 'Imported contacts. Only present when requested via `?include=records`.'
                    items:
                      type: object
                      properties:
                        model_id:
                          type: string
                          format: uuid
                          description: 'Id of the created / updated contact'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        is_new:
                          type: boolean
                          description: 'True when a new contact was created, false when an existing one was updated'
                          example: true
                        was_trashed:
                          type: boolean
                          description: 'True when a soft-deleted contact was restored by the import'
                          example: false
                  errors:
                    type: array
                    description: 'Row-level failures. Only present when requested via `?include=errors`.'
                    items:
                      type: object
                      properties:
                        row:
                          type: integer
                          description: '1-based row number in the uploaded file'
                          example: 7
                        attribute:
                          type:
                            - string
                            - 'null'
                          description: 'The field that failed validation, when applicable'
                          example: email
                        messages:
                          type: array
                          items:
                            type: string
                          example:
                            - 'The email must be a valid email address.'
                        row_data:
                          type: object
                          additionalProperties: true
                          description: 'The offending row as read from the file'
                          example:
                            name1: Jane
                            email: not-an-email
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: |
            Conflict. The import is no longer in a state that allows this action (for
            example, it has already been submitted for processing). Only an `incomplete`
            import can be configured or confirmed.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: Conflict
                properties:
                  message:
                    type: string
              example:
                message: 'This import has already been submitted.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/contacts/imports/{id}/confirm':
    post:
      tags:
        - ContactImports
      summary: 'Confirm and start an import (user)'
      operationId: postContactImportConfirm
      description: |
        Confirms an `incomplete` import and queues it for background processing. The
        import must have a saved mapping (`can_confirm: true`) or a 422 is returned.
        On success the import moves to `pending` and is processed asynchronously;
        poll the get-import endpoint for the final status and counts. Only an
        `incomplete` import can be confirmed (otherwise 409).

        Imports created in the Cockpit admin are not drivable here, and an import
        started via this API cannot be completed from the Cockpit admin: the two
        flows are kept separate.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Import identifier'
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. The import resource (unwrapped), now `pending`.'
          content:
            application/json:
              schema:
                type: object
                description: |
                  An API-driven contact import. Every import is strictly owner-scoped: a user
                  only ever sees and drives their own imports, and every contact it creates is
                  private to that user. The import moves through a small state machine:
                  `incomplete` (being configured) -> `pending` (queued) -> `processing` ->
                  `completed` / `completed_with_errors` / `failed`.

                  `records` and `errors` are opt-in via `?include=records,errors` and are omitted
                  otherwise.
                required:
                  - id
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Import identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  status:
                    type: string
                    description: 'Current stage of the import lifecycle'
                    enum:
                      - incomplete
                      - pending
                      - processing
                      - completed
                      - completed_with_errors
                      - failed
                    example: incomplete
                  file_type:
                    type:
                      - string
                      - 'null'
                    description: 'Detected type of the uploaded file'
                    enum:
                      - csv
                      - xls
                      - xlsx
                      - null
                    example: csv
                  records_count:
                    type: integer
                    description: 'Number of contacts imported (populated once processed)'
                    example: 42
                  errors_count:
                    type: integer
                    description: 'Number of rows that failed to import'
                    example: 3
                  can_confirm:
                    type: boolean
                    description: 'True when the import is still incomplete and has a saved mapping, so it may be confirmed'
                    example: true
                  header_row_position:
                    type:
                      - integer
                      - 'null'
                    description: '1-based row holding the column headers.'
                    example: 1
                  sheet_index:
                    type:
                      - integer
                      - 'null'
                    description: '0-based sheet to read (Excel files).'
                    example: null
                  delimiter:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field delimiter (auto-detected when null).'
                    example: null
                  enclosure:
                    type:
                      - string
                      - 'null'
                    description: 'CSV field enclosure character.'
                    example: '"'
                  input_encoding:
                    type:
                      - string
                      - 'null'
                    description: 'Character encoding of the file.'
                    example: UTF-8
                  skip_on_error:
                    type: boolean
                    description: 'When true, invalid rows are skipped instead of failing the import.'
                    example: true
                  notify_owner_by_email:
                    type: boolean
                    description: 'Whether the owner is emailed once the import finishes.'
                    example: false
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    format: uri
                    description: 'Client webhook that receives lifecycle events.'
                    example: null
                  mappings:
                    type: array
                    description: 'The saved column mapping, in the same shape it was submitted (empty until one is saved).'
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: name1
                        column:
                          type: integer
                          example: 0
                        subfields:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                                example: type
                              value:
                                type: string
                                example: mobile
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-01-15T09:30:00Z'
                    readOnly: true
                  started_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing began'
                    example: '2026-01-15T09:31:00Z'
                    readOnly: true
                  completed_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When background processing finished'
                    example: '2026-01-15T09:31:45Z'
                    readOnly: true
                  records:
                    type: array
                    description: 'Imported contacts. Only present when requested via `?include=records`.'
                    items:
                      type: object
                      properties:
                        model_id:
                          type: string
                          format: uuid
                          description: 'Id of the created / updated contact'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        is_new:
                          type: boolean
                          description: 'True when a new contact was created, false when an existing one was updated'
                          example: true
                        was_trashed:
                          type: boolean
                          description: 'True when a soft-deleted contact was restored by the import'
                          example: false
                  errors:
                    type: array
                    description: 'Row-level failures. Only present when requested via `?include=errors`.'
                    items:
                      type: object
                      properties:
                        row:
                          type: integer
                          description: '1-based row number in the uploaded file'
                          example: 7
                        attribute:
                          type:
                            - string
                            - 'null'
                          description: 'The field that failed validation, when applicable'
                          example: email
                        messages:
                          type: array
                          items:
                            type: string
                          example:
                            - 'The email must be a valid email address.'
                        row_data:
                          type: object
                          additionalProperties: true
                          description: 'The offending row as read from the file'
                          example:
                            name1: Jane
                            email: not-an-email
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: |
            Conflict. The import is no longer in a state that allows this action (for
            example, it has already been submitted for processing). Only an `incomplete`
            import can be configured or confirmed.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: Conflict
                properties:
                  message:
                    type: string
              example:
                message: 'This import has already been submitted.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /extensions:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Extensions
      summary: 'List extension'
      operationId: listExtensions
      description: |
        Returns a paginated list of extensions. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `number`, `description`, `assigned_to_type`, `user.show_in_address_book`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
        -
          name: include
          description: |
            Comma-separated related resources to embed (dot-nested where
            shown). Allowed: `famulorAgent`, `sipDevice`, `user`, `user.employee`, `user.groups`, `user.callerIdentities`, `user.callerIdentities.phoneNumber`, `user.sipDevices`, `user.twinnings`, `user.queues`, `user.queues.statuses`, `user.locations`.
          in: query
          required: false
          schema:
            type: string
          example: 'user,user.groups'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Internal dial number assigned to a user, device, queue, or other PBX entity.
                        Per-direction call recording is controlled by the two `record_*_calls` flags.
                        The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                        (always present); the full `assigned_to` object is opt-in.
                      required:
                        - id
                        - pbx_id
                        - number
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Extension identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        assigned_to_type:
                          type:
                            - string
                            - 'null'
                          description: 'Friendly type of the entity this extension is assigned to'
                          enum:
                            - user
                            - sip_device
                            - famulor_agent
                          example: user
                        assigned_to_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the entity this extension is assigned to'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to external inbound calls hitting this extension'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to internal calls hitting this extension'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        number:
                          type: string
                          maxLength: 16
                          description: 'Dialable extension digits'
                          example: '1337'
                        name:
                          type:
                            - string
                            - 'null'
                          description: 'Display name for the extension'
                          example: 'Support line'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Front-line support line'
                        record_external_calls:
                          type: boolean
                          description: 'Whether external calls on this extension are recorded'
                          example: true
                        record_internal_calls:
                          type: boolean
                          description: 'Whether internal calls on this extension are recorded'
                          example: false
                        sync_source:
                          type: string
                          description: 'Provisioning origin (cast to ExtensionSyncSource)'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          example: manual
                        full_name_with_extension_number:
                          type:
                            - string
                            - 'null'
                          description: "Convenience label combining the assignee's name and the extension number"
                          example: 'Jane Smith (1337)'
                          readOnly: true
                        assigned_to:
                          type: object
                          description: |
                            The resolved owner of this extension; shape varies by `assigned_to_type`.
                            Returned only when requested via `?include=user` (or `?include=sipDevice`
                            / `?include=famulorAgent`).
                        employee_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Identifier of the employee record linked to the assigned user.
                            Returned only when requested via `?include=user.employee`.
                          example: 550e8400-e29b-41d4-a716-446655440005
                        department_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Department of the assigned user's employee, taken from their currently
                            active contract (null when the employee has no active contract).
                            Returned only when requested via `?include=user.employee`.
                          example: 550e8400-e29b-41d4-a716-446655440006
                        is_favorite:
                          type: boolean
                          description: |
                            Whether the extension's user is one of the **calling user's** favourites.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/extensions/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Extensions
      summary: 'Get an Extension'
      operationId: getExtension
      description: |
        Returns the extension identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Internal dial number assigned to a user, device, queue, or other PBX entity.
                  Per-direction call recording is controlled by the two `record_*_calls` flags.
                  The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                  (always present); the full `assigned_to` object is opt-in.
                required:
                  - id
                  - pbx_id
                  - number
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Extension identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  assigned_to_type:
                    type:
                      - string
                      - 'null'
                    description: 'Friendly type of the entity this extension is assigned to'
                    enum:
                      - user
                      - sip_device
                      - famulor_agent
                    example: user
                  assigned_to_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the entity this extension is assigned to'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  external_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow applied to external inbound calls hitting this extension'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  internal_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow applied to internal calls hitting this extension'
                    example: 550e8400-e29b-41d4-a716-446655440004
                  number:
                    type: string
                    maxLength: 16
                    description: 'Dialable extension digits'
                    example: '1337'
                  name:
                    type:
                      - string
                      - 'null'
                    description: 'Display name for the extension'
                    example: 'Support line'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    example: 'Front-line support line'
                  record_external_calls:
                    type: boolean
                    description: 'Whether external calls on this extension are recorded'
                    example: true
                  record_internal_calls:
                    type: boolean
                    description: 'Whether internal calls on this extension are recorded'
                    example: false
                  sync_source:
                    type: string
                    description: 'Provisioning origin (cast to ExtensionSyncSource)'
                    enum:
                      - manual
                      - provision
                      - legacy_import
                    example: manual
                  full_name_with_extension_number:
                    type:
                      - string
                      - 'null'
                    description: "Convenience label combining the assignee's name and the extension number"
                    example: 'Jane Smith (1337)'
                    readOnly: true
                  assigned_to:
                    type: object
                    description: |
                      The resolved owner of this extension; shape varies by `assigned_to_type`.
                      Returned only when requested via `?include=user` (or `?include=sipDevice`
                      / `?include=famulorAgent`).
                  employee_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: |
                      Identifier of the employee record linked to the assigned user.
                      Returned only when requested via `?include=user.employee`.
                    example: 550e8400-e29b-41d4-a716-446655440005
                  department_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: |
                      Department of the assigned user's employee, taken from their currently
                      active contract (null when the employee has no active contract).
                      Returned only when requested via `?include=user.employee`.
                    example: 550e8400-e29b-41d4-a716-446655440006
                  is_favorite:
                    type: boolean
                    description: |
                      Whether the extension's user is one of the **calling user's** favourites.
                      PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                      OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                    example: false
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /favorite-extensions:
    get:
      tags:
        - Extensions
      summary: 'Get favorite extensions for the authenticated user'
      operationId: getExtensionFavorites
      description: |
        Returns a paginated list of extension favorites. Use the standard `search`, `sort`, `page`,
        and `perPage` query parameters; use `filter[key]=value` to narrow the result set.
        Multi-tenant scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                        pbx_id:
                          type: integer
                        extension:
                          type: string
                        user_id:
                          type:
                            - integer
                            - 'null'
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 1
                    pbx_id: 1
                    extension: '101'
                    user_id: 2
                    created_at: '2023-10-16T08:29:07.000000Z'
                    updated_at: '2023-10-16T08:29:07.000000Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /groups:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Groups
      summary: 'List group'
      operationId: listGroups
      description: |
        Returns a paginated list of groups. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `description`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
        -
          name: include
          description: |
            Comma-separated related resources to embed (dot-nested where
            shown). Allowed: `users`.
          in: query
          required: false
          schema:
            type: string
          example: users
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Group of users that share routing defaults and (optionally) a common caller
                        identity. Many fields are foreign keys pointing at defaults used when the
                        group's users place or receive calls.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Group identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for internal calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for external calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_outside_the_group:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension displayed to non-group members'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Default caller identity applied to the group's outbound calls"
                          example: 550e8400-e29b-41d4-a716-446655440004
                        external_uid:
                          type:
                            - string
                            - 'null'
                          description: 'External identifier from a CRM or directory sync'
                          example: grp-support
                        allow_call_pickups:
                          type: boolean
                          description: "Whether group members may pick up each others' ringing calls"
                          example: true
                        name:
                          type: string
                          maxLength: 64
                          example: 'Support team'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'First-line support'
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: "Whether the group's CIDs include the PBX-default outbound numbers"
                          example: false
                        display_tab_to_everyone_inside_voxbi:
                          type: boolean
                          description: "Whether the group's tab is shown to everyone in the PBX"
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        users:
                          type: array
                          description: |
                            Members of the group, each as a user reference. Returned only when
                            requested via `?include=users`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    default_internal_call_flow_id: 550e8400-e29b-41d4-a716-446655440002
                    default_external_call_flow_id: 550e8400-e29b-41d4-a716-446655440003
                    default_caller_identity_id: 550e8400-e29b-41d4-a716-446655440004
                    extension_id_shown_outside_the_group: 550e8400-e29b-41d4-a716-446655440005
                    name: 'Support team'
                    description: 'First-line support'
                    allow_call_pickups: true
                    allow_default_pbxes_outgoing_phone_numbers: false
                    display_tab_to_everyone_inside_voxbi: false
                    external_uid: grp-support
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - Groups
      summary: 'Create a group'
      operationId: createGroup
      description: |
        Create a group and optionally attach users, group permissions, and
        pickup-lines / phone numbers. `pbx_id` is forced from the authenticated user.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pbx_id
                - name
              properties:
                pbx_id:
                  type: string
                  format: uuid
                  description: "Pbx identifier (tenant). Must match the authenticated user's PBX."
                name:
                  type: string
                  minLength: 3
                  maxLength: 64
                description:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 255
                defaultInternalCallFlow:
                  type:
                    - string
                    - 'null'
                  format: uuid
                defaultExternalCallFlow:
                  type:
                    - string
                    - 'null'
                  format: uuid
                users:
                  type: array
                  description: 'Member user identifiers'
                  items:
                    type: string
                    format: uuid
                pickupUsers:
                  type: array
                  description: 'Users allowed to pick up calls in this group'
                  items:
                    type: string
                    format: uuid
                allowManageGroupContacts:
                  type: array
                  description: "Users allowed to manage this group's contacts"
                  items:
                    type: string
                    format: uuid
                allowAccessToGroupContacts:
                  type: array
                  description: "Users allowed to view this group's contacts"
                  items:
                    type: string
                    format: uuid
                phoneNumberAssignations:
                  type: array
                  description: 'Phone numbers attached to the group'
                  items:
                    type: string
                    format: uuid
                allow_call_pickups:
                  type: boolean
                  description: "Whether group members may pick up each others' ringing calls"
                allow_default_pbxes_outgoing_phone_numbers:
                  type: boolean
                  description: 'Whether the PBX-default outbound numbers are usable from this group'
                display_tab_to_everyone_inside_voxbi:
                  type: boolean
                  description: "Whether the group's tab is visible to all PBX users in Voxbi"
                callerIdentities:
                  type: array
                  description: 'Outbound caller identities exposed to the group'
                  items:
                    type: object
                    required:
                      - phoneNumber
                    properties:
                      phoneNumber:
                        type: string
                        format: uuid
                      suffix:
                        type:
                          - string
                          - 'null'
                        pattern: '^\d{0,5}\*?$'
                      label:
                        type:
                          - string
                          - 'null'
                        maxLength: 255
            example:
              pbx_id: 550e8400-e29b-41d4-a716-446655440001
              name: 'Customer Support'
              description: 'First-line support team'
              users:
                - 550e8400-e29b-41d4-a716-446655440010
                - 550e8400-e29b-41d4-a716-446655440011
              allow_call_pickups: true
              allow_default_pbxes_outgoing_phone_numbers: false
              display_tab_to_everyone_inside_voxbi: false
              callerIdentities:
                -
                  phoneNumber: 550e8400-e29b-41d4-a716-446655440020
                  suffix: '23'
                  label: 'Support line'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Group of users that share routing defaults and (optionally) a common caller
                      identity. Many fields are foreign keys pointing at defaults used when the
                      group's users place or receive calls.
                    required:
                      - id
                      - pbx_id
                      - name
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Group identifier'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Pbx identifier (tenant)'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      default_internal_call_flow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Call flow used for internal calls reaching this group'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      default_external_call_flow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Call flow used for external calls reaching this group'
                        example: 550e8400-e29b-41d4-a716-446655440003
                      extension_id_shown_outside_the_group:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Extension displayed to non-group members'
                        example: 550e8400-e29b-41d4-a716-446655440005
                      default_caller_identity_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: "Default caller identity applied to the group's outbound calls"
                        example: 550e8400-e29b-41d4-a716-446655440004
                      external_uid:
                        type:
                          - string
                          - 'null'
                        description: 'External identifier from a CRM or directory sync'
                        example: grp-support
                      allow_call_pickups:
                        type: boolean
                        description: "Whether group members may pick up each others' ringing calls"
                        example: true
                      name:
                        type: string
                        maxLength: 64
                        example: 'Support team'
                      description:
                        type:
                          - string
                          - 'null'
                        maxLength: 255
                        example: 'First-line support'
                      allow_default_pbxes_outgoing_phone_numbers:
                        type: boolean
                        description: "Whether the group's CIDs include the PBX-default outbound numbers"
                        example: false
                      display_tab_to_everyone_inside_voxbi:
                        type: boolean
                        description: "Whether the group's tab is shown to everyone in the PBX"
                        example: false
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      users:
                        type: array
                        description: |
                          Members of the group, each as a user reference. Returned only when
                          requested via `?include=users`.
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440006
                              readOnly: true
                            first_name:
                              type:
                                - string
                                - 'null'
                              example: Jane
                            last_name:
                              type:
                                - string
                                - 'null'
                              example: Smith
                            email:
                              type:
                                - string
                                - 'null'
                              format: email
                              example: jane.smith@example.com
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id: 550e8400-e29b-41d4-a716-446655440001
                  name: 'Customer Support'
                  description: 'First-line support team'
                  allow_call_pickups: true
                  allow_default_pbxes_outgoing_phone_numbers: false
                  display_tab_to_everyone_inside_voxbi: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/groups/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Groups
      summary: 'Get a Group'
      operationId: getGroup
      description: |
        Returns the group identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Group of users that share routing defaults and (optionally) a common caller
                  identity. Many fields are foreign keys pointing at defaults used when the
                  group's users place or receive calls.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Group identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  default_internal_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow used for internal calls reaching this group'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  default_external_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow used for external calls reaching this group'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  extension_id_shown_outside_the_group:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Extension displayed to non-group members'
                    example: 550e8400-e29b-41d4-a716-446655440005
                  default_caller_identity_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: "Default caller identity applied to the group's outbound calls"
                    example: 550e8400-e29b-41d4-a716-446655440004
                  external_uid:
                    type:
                      - string
                      - 'null'
                    description: 'External identifier from a CRM or directory sync'
                    example: grp-support
                  allow_call_pickups:
                    type: boolean
                    description: "Whether group members may pick up each others' ringing calls"
                    example: true
                  name:
                    type: string
                    maxLength: 64
                    example: 'Support team'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    example: 'First-line support'
                  allow_default_pbxes_outgoing_phone_numbers:
                    type: boolean
                    description: "Whether the group's CIDs include the PBX-default outbound numbers"
                    example: false
                  display_tab_to_everyone_inside_voxbi:
                    type: boolean
                    description: "Whether the group's tab is shown to everyone in the PBX"
                    example: false
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  users:
                    type: array
                    description: |
                      Members of the group, each as a user reference. Returned only when
                      requested via `?include=users`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440006
                          readOnly: true
                        first_name:
                          type:
                            - string
                            - 'null'
                          example: Jane
                        last_name:
                          type:
                            - string
                            - 'null'
                          example: Smith
                        email:
                          type:
                            - string
                            - 'null'
                          format: email
                          example: jane.smith@example.com
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/images/{modelType}/{modelId}':
    get:
      tags:
        - Images
      summary: 'List images for a model'
      operationId: getImageList
      description: |
        Returns the image list identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: modelType
          in: path
          description: 'The model type (e.g. user, contact)'
          required: true
          schema:
            type: string
            example: user
        -
          name: modelId
          in: path
          description: 'The model UUID'
          required: true
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Two-level keyed map of images, NOT a paginated list. Outer key is
                  the image type (from `ImageUploadType`); inner key is the usage
                  identifier (e.g. `avatar`, `wallpaper_main`).
                properties:
                  images:
                    type: object
                    description: 'Images keyed by type then by usage'
                    additionalProperties:
                      type: object
                      description: 'Map of usage -> image metadata for this type'
                      additionalProperties:
                        type: object
                        properties:
                          id:
                            type: integer
                          filename:
                            type: string
                          mime_type:
                            type: string
                          size:
                            type: integer
                            description: 'Size in bytes'
                          width:
                            type: integer
                          height:
                            type: integer
                          url:
                            type: string
                            format: uri
              example:
                images:
                  voxbi_desktop:
                    logo_main:
                      id: 12
                      filename: voxbi-logo.png
                      mime_type: image/png
                      size: 8421
                      width: 256
                      height: 64
                      url: 'https://cockpit.voxbi.com/api/v1/images/user/550e8400-e29b-41d4-a716-446655440000/logo_main?type=voxbi_desktop'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/images/{modelType}/{modelId}/{usage}':
    get:
      tags:
        - Images
      summary: 'Get a specific image for a model by usage'
      operationId: getImageGet
      description: |
        Returns the image get identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: modelType
          in: path
          description: 'The model type (e.g. user, contact)'
          required: true
          schema:
            type: string
            example: user
        -
          name: modelId
          in: path
          description: 'The model UUID'
          required: true
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: usage
          in: path
          description: 'Image usage identifier (e.g. avatar, thumbnail)'
          required: true
          schema:
            type: string
            example: avatar
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                      model_type:
                        type: string
                      model_id:
                        type: string
                        format: uuid
                      usage:
                        type: string
                      url:
                        type: string
                      created_at:
                        type: string
                        format: date-time
              example:
                data:
                  id: 1
                  model_type: user
                  model_id: 550e8400-e29b-41d4-a716-446655440000
                  usage: avatar
                  url: 'https://example.com/images/avatar.jpg'
                  created_at: '2023-10-16T08:29:07.000000Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /ivrs:
    get:
      tags:
        - IVR
      summary: 'List ivr'
      operationId: listIvrs
      description: |
        Returns a paginated list of ivrs. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, pbx_id, name and comment.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Interactive Voice Response (IVR) menu. An IVR plays a sound file announcement
                        and then routes the caller to a destination based on the digit they press. The
                        available digit-to-destination mappings are held on the related IVR steps,
                        returned inline in the `steps` array.
                      required:
                        - id
                        - pbx_id
                        - name
                        - announcement_id
                        - steps
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the IVR menu.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this IVR. All IVRs are scoped to a single tenant.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type: string
                          maxLength: 128
                          description: 'Human-readable label for the IVR menu, shown in the admin panel and used to identify the menu in call-flow configuration.'
                          example: 'Customer Support Menu'
                        comment:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Optional free-text note describing the purpose or behaviour of this IVR. May be null.'
                          example: 'After-hours routing for the support line'
                        announcement_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the SoundFile announcement played to the caller when they enter this IVR menu. The referenced sound file is of type `announcement`.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        announcement_language:
                          type:
                            - string
                            - 'null'
                          description: |
                            Language override for this IVR's announcement. `null` (Auto) plays the
                            language variant detected/inherited earlier in the call, falling back to the
                            parent announcement. An ISO-639-1 code forces that specific variant.
                          enum:
                            - en
                            - de
                            - fr
                            - lb
                            - es
                            - it
                            - pt
                            - nl
                            - pl
                            - ru
                            - tr
                            - sv
                            - da
                            - 'no'
                            - fi
                            - cs
                            - sk
                            - el
                            - hu
                            - ro
                            - bg
                            - hr
                            - uk
                            - ar
                            - he
                            - hi
                            - ja
                            - ko
                            - zh
                            - id
                            - ms
                            - th
                            - vi
                            - null
                          example: fr
                        steps:
                          type: array
                          description: |
                            Ordered collection of IVR steps belonging to this menu. Each step maps a
                            caller key press (or the default action) to a routing destination. The
                            array is empty when no steps have been configured yet.
                          items:
                            type: object
                            description: |
                              A single keypad option inside an IVR (Interactive Voice Response) menu. When a
                              caller reaches the parent IVR, the digit they press is matched against `option`
                              (or the `default` step when no digit is pressed before the timeout) and the call
                              is routed to the resource identified by the polymorphic `target_type` plus
                              `target_id` pair. Legal routing targets are call flows and other IVRs, allowing
                              nested menus.
                            required:
                              - id
                              - pbx_id
                              - ivr_id
                              - target_type
                              - target_id
                              - option
                              - created_at
                              - updated_at
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique identifier of the IVR step.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this IVR step.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              ivr_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the parent IVR menu this step belongs to.'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              target_type:
                                type: string
                                description: |
                                  Polymorphic morph class of the routing target, stored as the fully
                                  qualified PHP class name. Together with `target_id` it identifies where the
                                  call is routed when this option is selected. Valid targets are call flows
                                  and IVRs.
                                enum:
                                  - App\Models\CallFlow
                                  - App\Models\Ivr
                                example: App\Models\CallFlow
                              target_id:
                                type: string
                                format: uuid
                                description: |
                                  Identifier of the routing target resource. The kind of resource is given by
                                  `target_type` (a CallFlow or an Ivr).
                                example: 550e8400-e29b-41d4-a716-446655440003
                              name:
                                type:
                                  - string
                                  - 'null'
                                description: |
                                  Optional human-readable label for this step, shown in the admin UI to
                                  describe where the option routes. Null when no label has been set.
                                example: 'Sales department'
                              option:
                                type: string
                                description: |
                                  The DTMF key that selects this step. The special value `default` is the
                                  fallback applied when the caller does not press any key before the IVR
                                  timeout.
                                enum:
                                  - default
                                  - '0'
                                  - '1'
                                  - '2'
                                  - '3'
                                  - '4'
                                  - '5'
                                  - '6'
                                  - '7'
                                  - '8'
                                  - '9'
                                  - '*'
                                  - '#'
                                example: '1'
                              language:
                                type:
                                  - string
                                  - 'null'
                                description: |
                                  Announcement language override applied from this step onward. `null` (Auto)
                                  means the language detected/inherited earlier in the call is kept. ISO-639-1
                                  code otherwise.
                                enum:
                                  - en
                                  - de
                                  - fr
                                  - lb
                                  - es
                                  - it
                                  - pt
                                  - nl
                                  - pl
                                  - ru
                                  - tr
                                  - sv
                                  - da
                                  - 'no'
                                  - fi
                                  - cs
                                  - sk
                                  - el
                                  - hu
                                  - ro
                                  - bg
                                  - hr
                                  - uk
                                  - ar
                                  - he
                                  - hi
                                  - ja
                                  - ko
                                  - zh
                                  - id
                                  - ms
                                  - th
                                  - vi
                                  - null
                                example: fr
                              voip_ivr_btn_id:
                                type:
                                  - integer
                                  - 'null'
                                format: int32
                                description: |
                                  Legacy integer identifier used to correlate this step with the
                                  corresponding button on the VoIP platform side. Null for steps that have no
                                  legacy mapping.
                                example: 42
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the IVR step was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the IVR step was last updated.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              deleted_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: |
                                  Soft-delete timestamp. Null for active steps; set to the deletion time when
                                  the step has been soft-deleted.
                                example: null
                                readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    announcement_id: 550e8400-e29b-41d4-a716-446655440002
                    name: 'Support IVR'
                    comment: 'Used for after-hours routing'
                    default_action: repeat
                    voip_ivr_id: 1
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                    steps:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440000
                        pbx_id: 550e8400-e29b-41d4-a716-446655440001
                        ivr_id: 550e8400-e29b-41d4-a716-446655440002
                        name: 'Sales department'
                        option: '1'
                        target_type: App\Models\CallFlow
                        target_id: 550e8400-e29b-41d4-a716-446655440003
                        voip_ivr_btn_id: 1
                        created_at: '2024-03-01T08:29:07Z'
                        updated_at: '2024-03-01T08:29:07Z'
                        deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - IVR
      summary: 'Create an IVR'
      operationId: createIvr
      description: |
        Create an IVR menu. `announcement` is the SoundFile of type `announcement`
        played when entering the menu; `musicOnHold` is an optional SoundFile of
        type `music`. `default_action` controls what happens on caller timeout.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pbx_id
                - name
                - announcement
              properties:
                pbx_id:
                  type: string
                  format: uuid
                  description: "Pbx identifier (tenant). Must match the authenticated user's PBX."
                name:
                  type: string
                  minLength: 3
                  maxLength: 64
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                announcement:
                  type: string
                  format: uuid
                  description: 'Sound file (type=announcement) played at the start of the menu'
                musicOnHold:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Sound file (type=music) played while caller is on hold'
                default_action:
                  type: string
                  enum:
                    - hangup
                    - repeat
                    - default_step
                  description: 'Behaviour on caller timeout'
            example:
              pbx_id: 550e8400-e29b-41d4-a716-446655440001
              name: 'Support IVR'
              comment: 'Routes calls to sales or technical support'
              announcement: 550e8400-e29b-41d4-a716-446655440010
              musicOnHold: 550e8400-e29b-41d4-a716-446655440011
              default_action: repeat
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Interactive Voice Response (IVR) menu. An IVR plays a sound file announcement
                      and then routes the caller to a destination based on the digit they press. The
                      available digit-to-destination mappings are held on the related IVR steps,
                      returned inline in the `steps` array.
                    required:
                      - id
                      - pbx_id
                      - name
                      - announcement_id
                      - steps
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the IVR menu.'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the Pbx (tenant) that owns this IVR. All IVRs are scoped to a single tenant.'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      name:
                        type: string
                        maxLength: 128
                        description: 'Human-readable label for the IVR menu, shown in the admin panel and used to identify the menu in call-flow configuration.'
                        example: 'Customer Support Menu'
                      comment:
                        type:
                          - string
                          - 'null'
                        maxLength: 255
                        description: 'Optional free-text note describing the purpose or behaviour of this IVR. May be null.'
                        example: 'After-hours routing for the support line'
                      announcement_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the SoundFile announcement played to the caller when they enter this IVR menu. The referenced sound file is of type `announcement`.'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      announcement_language:
                        type:
                          - string
                          - 'null'
                        description: |
                          Language override for this IVR's announcement. `null` (Auto) plays the
                          language variant detected/inherited earlier in the call, falling back to the
                          parent announcement. An ISO-639-1 code forces that specific variant.
                        enum:
                          - en
                          - de
                          - fr
                          - lb
                          - es
                          - it
                          - pt
                          - nl
                          - pl
                          - ru
                          - tr
                          - sv
                          - da
                          - 'no'
                          - fi
                          - cs
                          - sk
                          - el
                          - hu
                          - ro
                          - bg
                          - hr
                          - uk
                          - ar
                          - he
                          - hi
                          - ja
                          - ko
                          - zh
                          - id
                          - ms
                          - th
                          - vi
                          - null
                        example: fr
                      steps:
                        type: array
                        description: |
                          Ordered collection of IVR steps belonging to this menu. Each step maps a
                          caller key press (or the default action) to a routing destination. The
                          array is empty when no steps have been configured yet.
                        items:
                          type: object
                          description: |
                            A single keypad option inside an IVR (Interactive Voice Response) menu. When a
                            caller reaches the parent IVR, the digit they press is matched against `option`
                            (or the `default` step when no digit is pressed before the timeout) and the call
                            is routed to the resource identified by the polymorphic `target_type` plus
                            `target_id` pair. Legal routing targets are call flows and other IVRs, allowing
                            nested menus.
                          required:
                            - id
                            - pbx_id
                            - ivr_id
                            - target_type
                            - target_id
                            - option
                            - created_at
                            - updated_at
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: 'Unique identifier of the IVR step.'
                              example: 550e8400-e29b-41d4-a716-446655440000
                              readOnly: true
                            pbx_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the Pbx (tenant) that owns this IVR step.'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            ivr_id:
                              type: string
                              format: uuid
                              description: 'Identifier of the parent IVR menu this step belongs to.'
                              example: 550e8400-e29b-41d4-a716-446655440002
                            target_type:
                              type: string
                              description: |
                                Polymorphic morph class of the routing target, stored as the fully
                                qualified PHP class name. Together with `target_id` it identifies where the
                                call is routed when this option is selected. Valid targets are call flows
                                and IVRs.
                              enum:
                                - App\Models\CallFlow
                                - App\Models\Ivr
                              example: App\Models\CallFlow
                            target_id:
                              type: string
                              format: uuid
                              description: |
                                Identifier of the routing target resource. The kind of resource is given by
                                `target_type` (a CallFlow or an Ivr).
                              example: 550e8400-e29b-41d4-a716-446655440003
                            name:
                              type:
                                - string
                                - 'null'
                              description: |
                                Optional human-readable label for this step, shown in the admin UI to
                                describe where the option routes. Null when no label has been set.
                              example: 'Sales department'
                            option:
                              type: string
                              description: |
                                The DTMF key that selects this step. The special value `default` is the
                                fallback applied when the caller does not press any key before the IVR
                                timeout.
                              enum:
                                - default
                                - '0'
                                - '1'
                                - '2'
                                - '3'
                                - '4'
                                - '5'
                                - '6'
                                - '7'
                                - '8'
                                - '9'
                                - '*'
                                - '#'
                              example: '1'
                            language:
                              type:
                                - string
                                - 'null'
                              description: |
                                Announcement language override applied from this step onward. `null` (Auto)
                                means the language detected/inherited earlier in the call is kept. ISO-639-1
                                code otherwise.
                              enum:
                                - en
                                - de
                                - fr
                                - lb
                                - es
                                - it
                                - pt
                                - nl
                                - pl
                                - ru
                                - tr
                                - sv
                                - da
                                - 'no'
                                - fi
                                - cs
                                - sk
                                - el
                                - hu
                                - ro
                                - bg
                                - hr
                                - uk
                                - ar
                                - he
                                - hi
                                - ja
                                - ko
                                - zh
                                - id
                                - ms
                                - th
                                - vi
                                - null
                              example: fr
                            voip_ivr_btn_id:
                              type:
                                - integer
                                - 'null'
                              format: int32
                              description: |
                                Legacy integer identifier used to correlate this step with the
                                corresponding button on the VoIP platform side. Null for steps that have no
                                legacy mapping.
                              example: 42
                            created_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              description: 'Timestamp when the IVR step was created.'
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            updated_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              description: 'Timestamp when the IVR step was last updated.'
                              example: '2024-03-01T08:29:07Z'
                              readOnly: true
                            deleted_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              description: |
                                Soft-delete timestamp. Null for active steps; set to the deletion time when
                                the step has been soft-deleted.
                              example: null
                              readOnly: true
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id: 550e8400-e29b-41d4-a716-446655440001
                  announcement_id: 550e8400-e29b-41d4-a716-446655440010
                  name: 'Support IVR'
                  comment: 'Routes calls to sales or technical support'
                  default_action: repeat
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/ivrs/{id}':
    get:
      tags:
        - IVR
      summary: 'Get an IVR'
      operationId: getIvr
      description: |
        Returns the ivr identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Interactive Voice Response (IVR) menu. An IVR plays a sound file announcement
                  and then routes the caller to a destination based on the digit they press. The
                  available digit-to-destination mappings are held on the related IVR steps,
                  returned inline in the `steps` array.
                required:
                  - id
                  - pbx_id
                  - name
                  - announcement_id
                  - steps
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the IVR menu.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this IVR. All IVRs are scoped to a single tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 128
                    description: 'Human-readable label for the IVR menu, shown in the admin panel and used to identify the menu in call-flow configuration.'
                    example: 'Customer Support Menu'
                  comment:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note describing the purpose or behaviour of this IVR. May be null.'
                    example: 'After-hours routing for the support line'
                  announcement_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the SoundFile announcement played to the caller when they enter this IVR menu. The referenced sound file is of type `announcement`.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  announcement_language:
                    type:
                      - string
                      - 'null'
                    description: |
                      Language override for this IVR's announcement. `null` (Auto) plays the
                      language variant detected/inherited earlier in the call, falling back to the
                      parent announcement. An ISO-639-1 code forces that specific variant.
                    enum:
                      - en
                      - de
                      - fr
                      - lb
                      - es
                      - it
                      - pt
                      - nl
                      - pl
                      - ru
                      - tr
                      - sv
                      - da
                      - 'no'
                      - fi
                      - cs
                      - sk
                      - el
                      - hu
                      - ro
                      - bg
                      - hr
                      - uk
                      - ar
                      - he
                      - hi
                      - ja
                      - ko
                      - zh
                      - id
                      - ms
                      - th
                      - vi
                      - null
                    example: fr
                  steps:
                    type: array
                    description: |
                      Ordered collection of IVR steps belonging to this menu. Each step maps a
                      caller key press (or the default action) to a routing destination. The
                      array is empty when no steps have been configured yet.
                    items:
                      type: object
                      description: |
                        A single keypad option inside an IVR (Interactive Voice Response) menu. When a
                        caller reaches the parent IVR, the digit they press is matched against `option`
                        (or the `default` step when no digit is pressed before the timeout) and the call
                        is routed to the resource identified by the polymorphic `target_type` plus
                        `target_id` pair. Legal routing targets are call flows and other IVRs, allowing
                        nested menus.
                      required:
                        - id
                        - pbx_id
                        - ivr_id
                        - target_type
                        - target_id
                        - option
                        - created_at
                        - updated_at
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the IVR step.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this IVR step.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        ivr_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the parent IVR menu this step belongs to.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        target_type:
                          type: string
                          description: |
                            Polymorphic morph class of the routing target, stored as the fully
                            qualified PHP class name. Together with `target_id` it identifies where the
                            call is routed when this option is selected. Valid targets are call flows
                            and IVRs.
                          enum:
                            - App\Models\CallFlow
                            - App\Models\Ivr
                          example: App\Models\CallFlow
                        target_id:
                          type: string
                          format: uuid
                          description: |
                            Identifier of the routing target resource. The kind of resource is given by
                            `target_type` (a CallFlow or an Ivr).
                          example: 550e8400-e29b-41d4-a716-446655440003
                        name:
                          type:
                            - string
                            - 'null'
                          description: |
                            Optional human-readable label for this step, shown in the admin UI to
                            describe where the option routes. Null when no label has been set.
                          example: 'Sales department'
                        option:
                          type: string
                          description: |
                            The DTMF key that selects this step. The special value `default` is the
                            fallback applied when the caller does not press any key before the IVR
                            timeout.
                          enum:
                            - default
                            - '0'
                            - '1'
                            - '2'
                            - '3'
                            - '4'
                            - '5'
                            - '6'
                            - '7'
                            - '8'
                            - '9'
                            - '*'
                            - '#'
                          example: '1'
                        language:
                          type:
                            - string
                            - 'null'
                          description: |
                            Announcement language override applied from this step onward. `null` (Auto)
                            means the language detected/inherited earlier in the call is kept. ISO-639-1
                            code otherwise.
                          enum:
                            - en
                            - de
                            - fr
                            - lb
                            - es
                            - it
                            - pt
                            - nl
                            - pl
                            - ru
                            - tr
                            - sv
                            - da
                            - 'no'
                            - fi
                            - cs
                            - sk
                            - el
                            - hu
                            - ro
                            - bg
                            - hr
                            - uk
                            - ar
                            - he
                            - hi
                            - ja
                            - ko
                            - zh
                            - id
                            - ms
                            - th
                            - vi
                            - null
                          example: fr
                        voip_ivr_btn_id:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: |
                            Legacy integer identifier used to correlate this step with the
                            corresponding button on the VoIP platform side. Null for steps that have no
                            legacy mapping.
                          example: 42
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the IVR step was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the IVR step was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        deleted_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: |
                            Soft-delete timestamp. Null for active steps; set to the deletion time when
                            the step has been soft-deleted.
                          example: null
                          readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                announcement_id: 550e8400-e29b-41d4-a716-446655440002
                name: 'Support IVR'
                comment: 'Used for after-hours routing'
                default_action: repeat
                voip_ivr_id: 1
                created_at: '2024-03-01T08:29:07Z'
                updated_at: '2024-03-01T08:29:07Z'
                deleted_at: '2024-03-01T08:29:07Z'
                steps:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    ivr_id: 550e8400-e29b-41d4-a716-446655440002
                    name: 'Sales department'
                    option: '1'
                    target_type: App\Models\CallFlow
                    target_id: 550e8400-e29b-41d4-a716-446655440003
                    voip_ivr_btn_id: 1
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /ivr-steps:
    get:
      tags:
        - 'IVR Steps'
      summary: 'List IVR step'
      operationId: listIvrSteps
      description: |
        Returns a paginated list of ivr steps. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, parent_id, ivr_id, sound_file_id, name, option, delay, action_type and action_value.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        A single keypad option inside an IVR (Interactive Voice Response) menu. When a
                        caller reaches the parent IVR, the digit they press is matched against `option`
                        (or the `default` step when no digit is pressed before the timeout) and the call
                        is routed to the resource identified by the polymorphic `target_type` plus
                        `target_id` pair. Legal routing targets are call flows and other IVRs, allowing
                        nested menus.
                      required:
                        - id
                        - pbx_id
                        - ivr_id
                        - target_type
                        - target_id
                        - option
                        - created_at
                        - updated_at
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the IVR step.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this IVR step.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        ivr_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the parent IVR menu this step belongs to.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        target_type:
                          type: string
                          description: |
                            Polymorphic morph class of the routing target, stored as the fully
                            qualified PHP class name. Together with `target_id` it identifies where the
                            call is routed when this option is selected. Valid targets are call flows
                            and IVRs.
                          enum:
                            - App\Models\CallFlow
                            - App\Models\Ivr
                          example: App\Models\CallFlow
                        target_id:
                          type: string
                          format: uuid
                          description: |
                            Identifier of the routing target resource. The kind of resource is given by
                            `target_type` (a CallFlow or an Ivr).
                          example: 550e8400-e29b-41d4-a716-446655440003
                        name:
                          type:
                            - string
                            - 'null'
                          description: |
                            Optional human-readable label for this step, shown in the admin UI to
                            describe where the option routes. Null when no label has been set.
                          example: 'Sales department'
                        option:
                          type: string
                          description: |
                            The DTMF key that selects this step. The special value `default` is the
                            fallback applied when the caller does not press any key before the IVR
                            timeout.
                          enum:
                            - default
                            - '0'
                            - '1'
                            - '2'
                            - '3'
                            - '4'
                            - '5'
                            - '6'
                            - '7'
                            - '8'
                            - '9'
                            - '*'
                            - '#'
                          example: '1'
                        language:
                          type:
                            - string
                            - 'null'
                          description: |
                            Announcement language override applied from this step onward. `null` (Auto)
                            means the language detected/inherited earlier in the call is kept. ISO-639-1
                            code otherwise.
                          enum:
                            - en
                            - de
                            - fr
                            - lb
                            - es
                            - it
                            - pt
                            - nl
                            - pl
                            - ru
                            - tr
                            - sv
                            - da
                            - 'no'
                            - fi
                            - cs
                            - sk
                            - el
                            - hu
                            - ro
                            - bg
                            - hr
                            - uk
                            - ar
                            - he
                            - hi
                            - ja
                            - ko
                            - zh
                            - id
                            - ms
                            - th
                            - vi
                            - null
                          example: fr
                        voip_ivr_btn_id:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: |
                            Legacy integer identifier used to correlate this step with the
                            corresponding button on the VoIP platform side. Null for steps that have no
                            legacy mapping.
                          example: 42
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the IVR step was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the IVR step was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        deleted_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: |
                            Soft-delete timestamp. Null for active steps; set to the deletion time when
                            the step has been soft-deleted.
                          example: null
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    ivr_id: 550e8400-e29b-41d4-a716-446655440002
                    name: 'Sales department'
                    option: '1'
                    target_type: App\Models\CallFlow
                    target_id: 550e8400-e29b-41d4-a716-446655440003
                    voip_ivr_btn_id: 1
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/ivr-steps/{id}':
    get:
      tags:
        - 'IVR Steps'
      summary: 'Get an IVR step'
      operationId: getIvrStep
      description: |
        Returns the ivr step identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  A single keypad option inside an IVR (Interactive Voice Response) menu. When a
                  caller reaches the parent IVR, the digit they press is matched against `option`
                  (or the `default` step when no digit is pressed before the timeout) and the call
                  is routed to the resource identified by the polymorphic `target_type` plus
                  `target_id` pair. Legal routing targets are call flows and other IVRs, allowing
                  nested menus.
                required:
                  - id
                  - pbx_id
                  - ivr_id
                  - target_type
                  - target_id
                  - option
                  - created_at
                  - updated_at
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the IVR step.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this IVR step.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  ivr_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the parent IVR menu this step belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  target_type:
                    type: string
                    description: |
                      Polymorphic morph class of the routing target, stored as the fully
                      qualified PHP class name. Together with `target_id` it identifies where the
                      call is routed when this option is selected. Valid targets are call flows
                      and IVRs.
                    enum:
                      - App\Models\CallFlow
                      - App\Models\Ivr
                    example: App\Models\CallFlow
                  target_id:
                    type: string
                    format: uuid
                    description: |
                      Identifier of the routing target resource. The kind of resource is given by
                      `target_type` (a CallFlow or an Ivr).
                    example: 550e8400-e29b-41d4-a716-446655440003
                  name:
                    type:
                      - string
                      - 'null'
                    description: |
                      Optional human-readable label for this step, shown in the admin UI to
                      describe where the option routes. Null when no label has been set.
                    example: 'Sales department'
                  option:
                    type: string
                    description: |
                      The DTMF key that selects this step. The special value `default` is the
                      fallback applied when the caller does not press any key before the IVR
                      timeout.
                    enum:
                      - default
                      - '0'
                      - '1'
                      - '2'
                      - '3'
                      - '4'
                      - '5'
                      - '6'
                      - '7'
                      - '8'
                      - '9'
                      - '*'
                      - '#'
                    example: '1'
                  language:
                    type:
                      - string
                      - 'null'
                    description: |
                      Announcement language override applied from this step onward. `null` (Auto)
                      means the language detected/inherited earlier in the call is kept. ISO-639-1
                      code otherwise.
                    enum:
                      - en
                      - de
                      - fr
                      - lb
                      - es
                      - it
                      - pt
                      - nl
                      - pl
                      - ru
                      - tr
                      - sv
                      - da
                      - 'no'
                      - fi
                      - cs
                      - sk
                      - el
                      - hu
                      - ro
                      - bg
                      - hr
                      - uk
                      - ar
                      - he
                      - hi
                      - ja
                      - ko
                      - zh
                      - id
                      - ms
                      - th
                      - vi
                      - null
                    example: fr
                  voip_ivr_btn_id:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    description: |
                      Legacy integer identifier used to correlate this step with the
                      corresponding button on the VoIP platform side. Null for steps that have no
                      legacy mapping.
                    example: 42
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the IVR step was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the IVR step was last updated.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  deleted_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: |
                      Soft-delete timestamp. Null for active steps; set to the deletion time when
                      the step has been soft-deleted.
                    example: null
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                ivr_id: 550e8400-e29b-41d4-a716-446655440002
                name: 'Sales department'
                option: '1'
                target_type: App\Models\CallFlow
                target_id: 550e8400-e29b-41d4-a716-446655440003
                voip_ivr_btn_id: 1
                created_at: '2024-03-01T08:29:07Z'
                updated_at: '2024-03-01T08:29:07Z'
                deleted_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /languages:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Languages
      summary: 'List language'
      operationId: listLanguages
      description: |
        Returns a paginated list of languages. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `id`, `name`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        A language defined for the tenant, used to label sound files, voice prompts
                        (IVR announcements), and per-user language preferences. Each language belongs
                        to exactly one Pbx (tenant) and is identified by a free-text name.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique language identifier (UUID).'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this language.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                          readOnly: true
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable language name as shown in the cockpit and selectors.'
                          example: English
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Languages
      summary: 'Create a language'
      operationId: createLanguage
      description: |
        Enable a language for the PBX. `name` must be one of the supported locale
        display names and unique within the PBX. `pbx_id` is forced from the
        authenticated principal (a user's PBX, or the Pbx-owned API key itself) and
        is never read from the request body.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 64
                  description: 'Supported locale display name (must be unique within the PBX)'
            example:
              name: English
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      A language defined for the tenant, used to label sound files, voice prompts
                      (IVR announcements), and per-user language preferences. Each language belongs
                      to exactly one Pbx (tenant) and is identified by a free-text name.
                    required:
                      - id
                      - pbx_id
                      - name
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique language identifier (UUID).'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the Pbx (tenant) that owns this language.'
                        example: 550e8400-e29b-41d4-a716-446655440001
                        readOnly: true
                      name:
                        type: string
                        maxLength: 64
                        description: 'Human-readable language name as shown in the cockpit and selectors.'
                        example: English
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/languages/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Languages
      summary: 'Get a Language'
      operationId: getLanguage
      description: |
        Returns the language identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  A language defined for the tenant, used to label sound files, voice prompts
                  (IVR announcements), and per-user language preferences. Each language belongs
                  to exactly one Pbx (tenant) and is identified by a free-text name.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique language identifier (UUID).'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this language.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                    readOnly: true
                  name:
                    type: string
                    maxLength: 64
                    description: 'Human-readable language name as shown in the cockpit and selectors.'
                    example: English
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /locations:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Locations
      summary: 'List location'
      operationId: listLocations
      description: |
        Returns a paginated list of locations. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `description`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Physical office or site associated with a PBX. Locations form a nested-set
                        tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                        used for emergency call routing.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Location identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        company_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Owning company identifier'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        parent_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Parent location identifier in the nested-set tree'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        name:
                          type: string
                          maxLength: 64
                          example: 'Luxembourg HQ'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Main office, 5th floor'
                        street_no:
                          type:
                            - string
                            - 'null'
                          description: 'Street number portion of the address'
                          example: '12'
                        street:
                          type:
                            - string
                            - 'null'
                          example: 'Main Street'
                        city:
                          type:
                            - string
                            - 'null'
                          example: Luxembourg
                        postal:
                          type:
                            - string
                            - 'null'
                          description: 'Postal code'
                          example: '1234'
                        country_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Country identifier'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        lft:
                          type:
                            - integer
                            - 'null'
                          description: 'Nested-set left bound'
                          example: 1
                        rgt:
                          type:
                            - integer
                            - 'null'
                          description: 'Nested-set right bound'
                          example: 10
                        depth:
                          type:
                            - integer
                            - 'null'
                          description: 'Tree depth (0 for root locations)'
                          example: 0
                        enable_location_as_presence_status:
                          type: boolean
                          description: 'Whether this location can be used as a presence status value'
                          example: false
                        style:
                          type:
                            - object
                            - 'null'
                          description: 'Optional presentation style (badge icon and colours) for the location'
                          example:
                            icon_class: la-map-pin
                            bg_color: '#3490dc'
                            font_color: '#ffffff'
                        is_fixed_location:
                          type: boolean
                          description: 'Whether this is a fixed (geofenced) physical location'
                          example: true
                        latitude:
                          type:
                            - number
                            - 'null'
                          format: float
                          description: 'Latitude of the location, in decimal degrees'
                          example: 49.6116
                        longitude:
                          type:
                            - number
                            - 'null'
                          format: float
                          description: 'Longitude of the location, in decimal degrees'
                          example: 6.1319
                        geofence_radius_m:
                          type:
                            - integer
                            - 'null'
                          description: 'Geofence radius around the location, in metres'
                          example: 100
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/locations/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Locations
      summary: 'Get a Location'
      operationId: getLocation
      description: |
        Returns the location identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Physical office or site associated with a PBX. Locations form a nested-set
                  tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                  used for emergency call routing.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Location identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  company_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Owning company identifier'
                    example: 550e8400-e29b-41d4-a716-446655440004
                  parent_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Parent location identifier in the nested-set tree'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  name:
                    type: string
                    maxLength: 64
                    example: 'Luxembourg HQ'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    example: 'Main office, 5th floor'
                  street_no:
                    type:
                      - string
                      - 'null'
                    description: 'Street number portion of the address'
                    example: '12'
                  street:
                    type:
                      - string
                      - 'null'
                    example: 'Main Street'
                  city:
                    type:
                      - string
                      - 'null'
                    example: Luxembourg
                  postal:
                    type:
                      - string
                      - 'null'
                    description: 'Postal code'
                    example: '1234'
                  country_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Country identifier'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  lft:
                    type:
                      - integer
                      - 'null'
                    description: 'Nested-set left bound'
                    example: 1
                  rgt:
                    type:
                      - integer
                      - 'null'
                    description: 'Nested-set right bound'
                    example: 10
                  depth:
                    type:
                      - integer
                      - 'null'
                    description: 'Tree depth (0 for root locations)'
                    example: 0
                  enable_location_as_presence_status:
                    type: boolean
                    description: 'Whether this location can be used as a presence status value'
                    example: false
                  style:
                    type:
                      - object
                      - 'null'
                    description: 'Optional presentation style (badge icon and colours) for the location'
                    example:
                      icon_class: la-map-pin
                      bg_color: '#3490dc'
                      font_color: '#ffffff'
                  is_fixed_location:
                    type: boolean
                    description: 'Whether this is a fixed (geofenced) physical location'
                    example: true
                  latitude:
                    type:
                      - number
                      - 'null'
                    format: float
                    description: 'Latitude of the location, in decimal degrees'
                    example: 49.6116
                  longitude:
                    type:
                      - number
                      - 'null'
                    format: float
                    description: 'Longitude of the location, in decimal degrees'
                    example: 6.1319
                  geofence_radius_m:
                    type:
                      - integer
                      - 'null'
                    description: 'Geofence radius around the location, in metres'
                    example: 100
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /pbxes:
    get:
      tags:
        - Pbxes
      summary: 'List pbxe'
      operationId: listPbxes
      description: |
        Returns a paginated list of pbxes. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, default_carrier_id, fallback_carrier_id, profile_id, name, comment, reserved_extensions, emergency, automatic_firmware, default_call_pickups_for_new_extensions, phones_default_vlan_pc, phones_default_vlan_phone, phones_web_admin_password, lldp, show_users_first_name_first, allow_changing_record_calls, recordings_destination, oidc_enabled, oidc_allow_sign_up, oidc_email_domain, oidc_client_id, oidc_client_secret, oidc_discover_url, oidc_authorization_url, oidc_token_url, oidc_userinfo_url, oidc_logout_url, oidc_issuer and oidc_identity_fields_mapping.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        The tenant container. Every other resource in the API is scoped to a single
                        Pbx. A Pbx carries the telephony defaults, provisioning state, SSO settings,
                        AI/transcription options, capacity estimates, and branding for one customer
                        instance.

                        SSO is configured through `sso_enabled` plus `sso_type` (`openid_connect` or
                        `microsoft`) and the `sso_identity_fields_mapping` JSON; the actual OIDC
                        endpoint details live on the related `IdentityProvider` records, not on this
                        object.

                        Hidden fields (`api_key`, `impersonation_token`, `user_provisioning_key`,
                        `user_provisioning_ip_addresses`, `phones_web_admin_password`) are listed in
                        `$hidden` on the model. They are accepted in write requests but are never
                        returned in any API response, so they are documented here as `writeOnly`.
                      required:
                        - id
                        - name
                        - instance_name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the Pbx tenant.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        partner_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the partner (reseller) that manages this Pbx, or null if managed directly.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        customer_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the customer record linked to this Pbx, or null if none is linked.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_carrier_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the default outbound SIP carrier used for external calls.'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        fallback_carrier_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the fallback SIP carrier used when the default carrier is unreachable.'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to internal calls that have no more specific routing.'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to external calls that have no more specific routing.'
                          example: 550e8400-e29b-41d4-a716-446655440006
                        no_ext_match_callflow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used when an inbound call matches no extension on the Pbx.'
                          example: 550e8400-e29b-41d4-a716-446655440007
                        profile_id:
                          type:
                            - integer
                            - 'null'
                          format: int64
                          description: 'Legacy numeric profile identifier carried over from the previous platform.'
                          example: 42
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable display name of the Pbx tenant.'
                          example: 'Acme Corp'
                        instance_name:
                          type: string
                          maxLength: 50
                          description: 'Internal instance slug, unique across the platform and used to build deployment hostnames.'
                          example: pbx16dev
                        trunk_username:
                          type:
                            - string
                            - 'null'
                          maxLength: 64
                          description: 'SIP trunk authentication username.'
                          example: trunk_acme
                        comment:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Free-form internal comment about the Pbx.'
                          example: 'Migrated from legacy platform in March'
                        reserved_extensions:
                          type: string
                          description: |
                            Comma-separated list of extension numbers reserved from automatic
                            assignment. Stored internally as JSON but always returned as a
                            comma-and-space joined string (empty string when none are reserved).
                          example: '112, 113, 911'
                        emergency:
                          type: boolean
                          description: 'Whether emergency-call handling is enabled for this Pbx.'
                          example: false
                        automatic_firmware:
                          type: boolean
                          description: 'Whether managed device firmware updates are applied automatically.'
                          example: true
                        default_call_pickups_for_new_extensions:
                          type: boolean
                          description: 'Whether newly created extensions get call-pickup enabled by default.'
                          example: true
                        allow_roaming:
                          type: boolean
                          description: 'Whether users may hot-desk (roam) between SIP devices.'
                          example: true
                        phones_default_vlan_pc:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: 'Default VLAN id assigned to the PC pass-through port on managed phones.'
                          example: 200
                        phones_default_vlan_phone:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: 'Default VLAN id assigned to the voice interface on managed phones.'
                          example: 100
                        phones_web_admin_password:
                          type: string
                          writeOnly: true
                          description: |
                            Administrative password for the web interface of managed phones. Accepted
                            in write requests but never returned (listed in the model `$hidden`).
                        lldp:
                          type: boolean
                          description: 'Whether Link Layer Discovery Protocol is enabled on managed phones.'
                          example: true
                        show_users_first_name_first:
                          type: boolean
                          description: 'Whether user display names are formatted with the first name before the last name.'
                          example: true
                        capitalize_users_last_name:
                          type: boolean
                          description: 'Whether user last names are rendered in uppercase.'
                          example: false
                        allow_call_recording:
                          type: boolean
                          description: 'Whether call recording is enabled tenant-wide.'
                          example: false
                        allow_changing_record_calls:
                          type: boolean
                          description: 'Whether users may override the per-call recording behaviour.'
                          example: false
                        recordings_destination:
                          type: string
                          description: 'Where call recordings are stored.'
                          enum:
                            - mixvoip
                            - customer
                          example: mixvoip
                        recording_start_at:
                          type: string
                          description: 'At which point recording begins within a call.'
                          enum:
                            - on_start
                            - on_bridge
                          example: on_start
                        user_provisioning_key:
                          type: string
                          writeOnly: true
                          description: |
                            Secret key used to authenticate the user-provisioning API. Accepted in
                            write requests but never returned (listed in the model `$hidden`).
                        user_provisioning_ip_addresses:
                          type: array
                          writeOnly: true
                          items:
                            type: string
                          description: |
                            Allow-list of IP addresses permitted to call the user-provisioning API.
                            Accepted in write requests but never returned (listed in the model
                            `$hidden`).
                        it_admin_notification_email:
                          type:
                            - string
                            - 'null'
                          format: email
                          maxLength: 255
                          description: 'Email address that receives IT administrator notifications for this Pbx.'
                          example: it@example.com
                        impersonation_token:
                          type: string
                          writeOnly: true
                          description: |
                            Token used by support staff to impersonate the tenant. Accepted in write
                            requests but never returned (listed in the model `$hidden`).
                        force_provisioning_sync:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp marking when a full provisioning re-sync was last forced. Returned as a string.'
                          example: '2024-03-01T08:29:07Z'
                        push_configuration:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last configuration push request. Returned as a string.'
                          example: '2024-03-01T08:29:07Z'
                        push_contact:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last contact-data push request. Returned as a string.'
                          example: '2024-03-01T08:29:07Z'
                        push_required:
                          type: boolean
                          description: 'Whether the Pbx has pending configuration changes that still need to be pushed to the server.'
                          example: false
                        push_check_pending:
                          type: boolean
                          description: 'Whether a configuration-push status check is currently in progress.'
                          example: false
                        push_check_requested_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the most recent push status check was requested.'
                          example: '2024-03-01T08:29:07Z'
                        push_required_count:
                          type: integer
                          format: int32
                          description: 'Number of configuration changes that require a push to the server.'
                          example: 0
                        push_other_count:
                          type: integer
                          format: int32
                          description: 'Number of non-critical pending changes tracked alongside required pushes.'
                          example: 0
                        server_push_date:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last successful configuration push applied on the server. Returned as a string.'
                          example: '2024-03-01T08:29:07Z'
                        contact_push_date:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last successful contact-data push applied on the server. Returned as a string.'
                          example: '2024-03-01T08:29:07Z'
                        last_config_update:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last configuration change made to the Pbx.'
                          example: '2024-03-01T08:29:07Z'
                        tenant_id:
                          type:
                            - string
                            - 'null'
                          description: 'External tenant identifier (for example the Microsoft Entra tenant id).'
                          example: 550e8400-e29b-41d4-a716-446655440099
                        sso_enabled:
                          type: boolean
                          description: 'Whether single sign-on is enabled for this Pbx.'
                          example: false
                        sso_type:
                          type:
                            - string
                            - 'null'
                          description: 'Single sign-on scheme in use, or null when SSO is disabled.'
                          enum:
                            - openid_connect
                            - microsoft
                          example: openid_connect
                        allow_sign_up_with_sso:
                          type: boolean
                          description: 'Whether new users may self-register through SSO.'
                          example: false
                        force_sign_in_with_sso:
                          type: boolean
                          description: 'Whether password sign-in is blocked and SSO is mandatory.'
                          example: false
                        max_incoming_channels:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: 'Maximum number of simultaneous inbound channels permitted on this Pbx.'
                          example: 50
                        max_incoming_channels_sound_file_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the SoundFile played to callers when the inbound channel limit is reached.'
                          example: 550e8400-e29b-41d4-a716-446655440008
                        music_on_hold_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the SoundFile used as the default music on hold.'
                          example: 550e8400-e29b-41d4-a716-446655440009
                        api_key:
                          type: string
                          writeOnly: true
                          description: |
                            Secret API key for the Pbx, used for provisioning authentication.
                            Accepted in write requests but never returned (listed in the model
                            `$hidden`).
                        sso_identity_fields_mapping:
                          type:
                            - object
                            - 'null'
                          description: |
                            Mapping from internal user fields to the SSO claim names that supply
                            their values. Returns null when SSO field mapping is not configured.
                          additionalProperties: true
                          example:
                            first_name: given_name
                            last_name: family_name
                            email: email
                        default_call_ring_duration:
                          type: integer
                          format: int32
                          description: 'Default ring duration in seconds applied across the Pbx.'
                          example: 30
                        enable_soop_status:
                          type: boolean
                          description: 'Whether the SOOP (status) presence feature is enabled for this Pbx.'
                          example: true
                        ai_profile:
                          type:
                            - string
                            - 'null'
                          description: |
                            Selected AI capability profile that determines which AI features are
                            available and how they behave. Null when no AI profile is assigned.
                          enum:
                            - basic
                            - premium
                            - unlimited
                          example: premium
                        ai_engine_status:
                          type: boolean
                          description: 'Whether the AI engine (transcription and summaries) is enabled for this Pbx.'
                          example: false
                        transcript_retention_days:
                          type:
                            - integer
                            - 'null'
                          format: int32
                          description: 'Number of days AI call transcripts are retained before deletion.'
                          example: 30
                        last_ai_engine_status_activity_check:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp of the last AI engine activity status check.'
                          example: '2024-03-01T08:29:07Z'
                        ring_tone:
                          type: string
                          description: 'Country code selecting the ringtone profile used by managed phones.'
                          enum:
                            - lu
                            - de
                            - fr
                            - be
                            - nl
                            - us
                            - uk
                            - pt
                            - ch
                            - at
                            - it
                            - es
                            - bg
                            - za
                          example: lu
                        show_all_users_in_voxbi:
                          type: boolean
                          description: 'Whether all tenant users are visible in the Voxbi softphone directory.'
                          example: true
                        split_internal_external_calls:
                          type: boolean
                          description: 'Whether internal and external calls are presented and routed separately.'
                          example: false
                        call_block_logged_out_sip_devices:
                          type: boolean
                          description: 'Whether outbound calls are blocked on SIP devices whose user is logged out.'
                          example: true
                        show_via_in_missed_call:
                          type: boolean
                          description: 'Whether the "via" routing information is shown on missed-call notifications.'
                          example: false
                        enable_tempus_menu:
                          type: boolean
                          description: 'Whether the Tempus time and attendance module menu is visible to this tenant.'
                          example: true
                        language:
                          type: string
                          description: 'Default UI language for the Pbx.'
                          enum:
                            - en
                            - de
                            - fr
                          example: en
                        estimated_users:
                          type: integer
                          format: int32
                          description: 'Estimated number of billable users on this Pbx.'
                          example: 25
                        estimated_sip_devices:
                          type: integer
                          format: int32
                          description: 'Estimated number of billable SIP devices on this Pbx.'
                          example: 30
                        multicast_sites_ip_addresses:
                          type:
                            - array
                            - 'null'
                          description: 'IP addresses of the Mikrotik routers used for multicast paging, or null when none are configured.'
                          items:
                            type: string
                          example:
                            - 10.10.0.1
                            - 10.10.0.2
                        flags:
                          type:
                            - object
                            - 'null'
                          description: 'Free-form feature-flag bag for tenant-specific opt-ins. Null when no flags are set.'
                          additionalProperties: true
                          example:
                            beta_dashboard: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the Pbx was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the Pbx was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        deleted_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the Pbx was soft-deleted, or null if active.'
                          example: null
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    name: 'Acme Corp'
                    instance_name: pbx16dev
                    partner_id: 550e8400-e29b-41d4-a716-446655440001
                    customer_id: 550e8400-e29b-41d4-a716-446655440002
                    profile_id: 42
                    default_carrier_id: 550e8400-e29b-41d4-a716-446655440003
                    fallback_carrier_id: 550e8400-e29b-41d4-a716-446655440004
                    default_internal_call_flow_id: 550e8400-e29b-41d4-a716-446655440005
                    default_external_call_flow_id: 550e8400-e29b-41d4-a716-446655440006
                    no_ext_match_callflow_id: 550e8400-e29b-41d4-a716-446655440007
                    default_call_flow_id: 550e8400-e29b-41d4-a716-446655440008
                    default_caller_id: '+12125550100'
                    music_on_hold_id: 550e8400-e29b-41d4-a716-446655440009
                    max_incoming_channels: 50
                    max_incoming_channels_sound_file_id: 550e8400-e29b-41d4-a716-446655440000
                    trunk_username: trunk_acme
                    reserved_extensions: '00, 11'
                    emergency: true
                    automatic_firmware: true
                    default_call_pickups_for_new_extensions: true
                    allow_roaming: true
                    phones_default_vlan_pc: 200
                    phones_default_vlan_phone: 100
                    lldp: true
                    show_users_first_name_first: true
                    capitalize_users_last_name: false
                    default_call_ring_duration: 30
                    ring_tone: lu
                    language: en
                    allow_call_recording: true
                    allow_changing_record_calls: true
                    recordings_destination: mixvoip
                    recording_start_at: on_bridge
                    transcript_retention_days: 30
                    sso_enabled: false
                    sso_type: openid_connect
                    allow_sign_up_with_sso: false
                    force_sign_in_with_sso: false
                    sso_identity_fields_mapping:
                      first_name: given_name
                      last_name: family_name
                      email: email
                    server_push_date: '2024-03-01T08:29:07Z'
                    contact_push_date: '2024-03-01T08:29:07Z'
                    push_required: false
                    push_check_pending: false
                    push_check_requested_at: '2024-03-01T08:29:07Z'
                    push_required_count: 0
                    push_other_count: 0
                    last_config_update: '2024-03-01T08:29:07Z'
                    it_admin_notification_email: it@example.com
                    ai_engine_status: false
                    last_ai_engine_status_activity_check: '2024-03-01T08:29:07Z'
                    microsoft365_integration_enabled: false
                    microsoft365_admin_consent_status: false
                    enable_soop_status: false
                    enable_tempus_menu: true
                    show_all_users_in_voxbi: true
                    show_via_in_missed_call: false
                    split_internal_external_calls: false
                    call_block_logged_out_sip_devices: false
                    estimated_users: 25
                    estimated_sip_devices: 30
                    multicast_sites_ip_addresses:
                      - 10.10.0.1
                      - 10.10.0.2
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/pbxes/{id}':
    get:
      tags:
        - Pbxes
      summary: 'Get a Pbx'
      operationId: getPbx
      description: |
        Returns the pbx identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  The tenant container. Every other resource in the API is scoped to a single
                  Pbx. A Pbx carries the telephony defaults, provisioning state, SSO settings,
                  AI/transcription options, capacity estimates, and branding for one customer
                  instance.

                  SSO is configured through `sso_enabled` plus `sso_type` (`openid_connect` or
                  `microsoft`) and the `sso_identity_fields_mapping` JSON; the actual OIDC
                  endpoint details live on the related `IdentityProvider` records, not on this
                  object.

                  Hidden fields (`api_key`, `impersonation_token`, `user_provisioning_key`,
                  `user_provisioning_ip_addresses`, `phones_web_admin_password`) are listed in
                  `$hidden` on the model. They are accepted in write requests but are never
                  returned in any API response, so they are documented here as `writeOnly`.
                required:
                  - id
                  - name
                  - instance_name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the Pbx tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  partner_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the partner (reseller) that manages this Pbx, or null if managed directly.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  customer_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the customer record linked to this Pbx, or null if none is linked.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  default_carrier_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the default outbound SIP carrier used for external calls.'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  fallback_carrier_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the fallback SIP carrier used when the default carrier is unreachable.'
                    example: 550e8400-e29b-41d4-a716-446655440004
                  default_internal_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow applied to internal calls that have no more specific routing.'
                    example: 550e8400-e29b-41d4-a716-446655440005
                  default_external_call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow applied to external calls that have no more specific routing.'
                    example: 550e8400-e29b-41d4-a716-446655440006
                  no_ext_match_callflow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Call flow used when an inbound call matches no extension on the Pbx.'
                    example: 550e8400-e29b-41d4-a716-446655440007
                  profile_id:
                    type:
                      - integer
                      - 'null'
                    format: int64
                    description: 'Legacy numeric profile identifier carried over from the previous platform.'
                    example: 42
                  name:
                    type: string
                    maxLength: 64
                    description: 'Human-readable display name of the Pbx tenant.'
                    example: 'Acme Corp'
                  instance_name:
                    type: string
                    maxLength: 50
                    description: 'Internal instance slug, unique across the platform and used to build deployment hostnames.'
                    example: pbx16dev
                  trunk_username:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: 'SIP trunk authentication username.'
                    example: trunk_acme
                  comment:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Free-form internal comment about the Pbx.'
                    example: 'Migrated from legacy platform in March'
                  reserved_extensions:
                    type: string
                    description: |
                      Comma-separated list of extension numbers reserved from automatic
                      assignment. Stored internally as JSON but always returned as a
                      comma-and-space joined string (empty string when none are reserved).
                    example: '112, 113, 911'
                  emergency:
                    type: boolean
                    description: 'Whether emergency-call handling is enabled for this Pbx.'
                    example: false
                  automatic_firmware:
                    type: boolean
                    description: 'Whether managed device firmware updates are applied automatically.'
                    example: true
                  default_call_pickups_for_new_extensions:
                    type: boolean
                    description: 'Whether newly created extensions get call-pickup enabled by default.'
                    example: true
                  allow_roaming:
                    type: boolean
                    description: 'Whether users may hot-desk (roam) between SIP devices.'
                    example: true
                  phones_default_vlan_pc:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    description: 'Default VLAN id assigned to the PC pass-through port on managed phones.'
                    example: 200
                  phones_default_vlan_phone:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    description: 'Default VLAN id assigned to the voice interface on managed phones.'
                    example: 100
                  phones_web_admin_password:
                    type: string
                    writeOnly: true
                    description: |
                      Administrative password for the web interface of managed phones. Accepted
                      in write requests but never returned (listed in the model `$hidden`).
                  lldp:
                    type: boolean
                    description: 'Whether Link Layer Discovery Protocol is enabled on managed phones.'
                    example: true
                  show_users_first_name_first:
                    type: boolean
                    description: 'Whether user display names are formatted with the first name before the last name.'
                    example: true
                  capitalize_users_last_name:
                    type: boolean
                    description: 'Whether user last names are rendered in uppercase.'
                    example: false
                  allow_call_recording:
                    type: boolean
                    description: 'Whether call recording is enabled tenant-wide.'
                    example: false
                  allow_changing_record_calls:
                    type: boolean
                    description: 'Whether users may override the per-call recording behaviour.'
                    example: false
                  recordings_destination:
                    type: string
                    description: 'Where call recordings are stored.'
                    enum:
                      - mixvoip
                      - customer
                    example: mixvoip
                  recording_start_at:
                    type: string
                    description: 'At which point recording begins within a call.'
                    enum:
                      - on_start
                      - on_bridge
                    example: on_start
                  user_provisioning_key:
                    type: string
                    writeOnly: true
                    description: |
                      Secret key used to authenticate the user-provisioning API. Accepted in
                      write requests but never returned (listed in the model `$hidden`).
                  user_provisioning_ip_addresses:
                    type: array
                    writeOnly: true
                    items:
                      type: string
                    description: |
                      Allow-list of IP addresses permitted to call the user-provisioning API.
                      Accepted in write requests but never returned (listed in the model
                      `$hidden`).
                  it_admin_notification_email:
                    type:
                      - string
                      - 'null'
                    format: email
                    maxLength: 255
                    description: 'Email address that receives IT administrator notifications for this Pbx.'
                    example: it@example.com
                  impersonation_token:
                    type: string
                    writeOnly: true
                    description: |
                      Token used by support staff to impersonate the tenant. Accepted in write
                      requests but never returned (listed in the model `$hidden`).
                  force_provisioning_sync:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp marking when a full provisioning re-sync was last forced. Returned as a string.'
                    example: '2024-03-01T08:29:07Z'
                  push_configuration:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last configuration push request. Returned as a string.'
                    example: '2024-03-01T08:29:07Z'
                  push_contact:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last contact-data push request. Returned as a string.'
                    example: '2024-03-01T08:29:07Z'
                  push_required:
                    type: boolean
                    description: 'Whether the Pbx has pending configuration changes that still need to be pushed to the server.'
                    example: false
                  push_check_pending:
                    type: boolean
                    description: 'Whether a configuration-push status check is currently in progress.'
                    example: false
                  push_check_requested_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the most recent push status check was requested.'
                    example: '2024-03-01T08:29:07Z'
                  push_required_count:
                    type: integer
                    format: int32
                    description: 'Number of configuration changes that require a push to the server.'
                    example: 0
                  push_other_count:
                    type: integer
                    format: int32
                    description: 'Number of non-critical pending changes tracked alongside required pushes.'
                    example: 0
                  server_push_date:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last successful configuration push applied on the server. Returned as a string.'
                    example: '2024-03-01T08:29:07Z'
                  contact_push_date:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last successful contact-data push applied on the server. Returned as a string.'
                    example: '2024-03-01T08:29:07Z'
                  last_config_update:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last configuration change made to the Pbx.'
                    example: '2024-03-01T08:29:07Z'
                  tenant_id:
                    type:
                      - string
                      - 'null'
                    description: 'External tenant identifier (for example the Microsoft Entra tenant id).'
                    example: 550e8400-e29b-41d4-a716-446655440099
                  sso_enabled:
                    type: boolean
                    description: 'Whether single sign-on is enabled for this Pbx.'
                    example: false
                  sso_type:
                    type:
                      - string
                      - 'null'
                    description: 'Single sign-on scheme in use, or null when SSO is disabled.'
                    enum:
                      - openid_connect
                      - microsoft
                    example: openid_connect
                  allow_sign_up_with_sso:
                    type: boolean
                    description: 'Whether new users may self-register through SSO.'
                    example: false
                  force_sign_in_with_sso:
                    type: boolean
                    description: 'Whether password sign-in is blocked and SSO is mandatory.'
                    example: false
                  max_incoming_channels:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    description: 'Maximum number of simultaneous inbound channels permitted on this Pbx.'
                    example: 50
                  max_incoming_channels_sound_file_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the SoundFile played to callers when the inbound channel limit is reached.'
                    example: 550e8400-e29b-41d4-a716-446655440008
                  music_on_hold_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the SoundFile used as the default music on hold.'
                    example: 550e8400-e29b-41d4-a716-446655440009
                  api_key:
                    type: string
                    writeOnly: true
                    description: |
                      Secret API key for the Pbx, used for provisioning authentication.
                      Accepted in write requests but never returned (listed in the model
                      `$hidden`).
                  sso_identity_fields_mapping:
                    type:
                      - object
                      - 'null'
                    description: |
                      Mapping from internal user fields to the SSO claim names that supply
                      their values. Returns null when SSO field mapping is not configured.
                    additionalProperties: true
                    example:
                      first_name: given_name
                      last_name: family_name
                      email: email
                  default_call_ring_duration:
                    type: integer
                    format: int32
                    description: 'Default ring duration in seconds applied across the Pbx.'
                    example: 30
                  enable_soop_status:
                    type: boolean
                    description: 'Whether the SOOP (status) presence feature is enabled for this Pbx.'
                    example: true
                  ai_profile:
                    type:
                      - string
                      - 'null'
                    description: |
                      Selected AI capability profile that determines which AI features are
                      available and how they behave. Null when no AI profile is assigned.
                    enum:
                      - basic
                      - premium
                      - unlimited
                    example: premium
                  ai_engine_status:
                    type: boolean
                    description: 'Whether the AI engine (transcription and summaries) is enabled for this Pbx.'
                    example: false
                  transcript_retention_days:
                    type:
                      - integer
                      - 'null'
                    format: int32
                    description: 'Number of days AI call transcripts are retained before deletion.'
                    example: 30
                  last_ai_engine_status_activity_check:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp of the last AI engine activity status check.'
                    example: '2024-03-01T08:29:07Z'
                  ring_tone:
                    type: string
                    description: 'Country code selecting the ringtone profile used by managed phones.'
                    enum:
                      - lu
                      - de
                      - fr
                      - be
                      - nl
                      - us
                      - uk
                      - pt
                      - ch
                      - at
                      - it
                      - es
                      - bg
                      - za
                    example: lu
                  show_all_users_in_voxbi:
                    type: boolean
                    description: 'Whether all tenant users are visible in the Voxbi softphone directory.'
                    example: true
                  split_internal_external_calls:
                    type: boolean
                    description: 'Whether internal and external calls are presented and routed separately.'
                    example: false
                  call_block_logged_out_sip_devices:
                    type: boolean
                    description: 'Whether outbound calls are blocked on SIP devices whose user is logged out.'
                    example: true
                  show_via_in_missed_call:
                    type: boolean
                    description: 'Whether the "via" routing information is shown on missed-call notifications.'
                    example: false
                  enable_tempus_menu:
                    type: boolean
                    description: 'Whether the Tempus time and attendance module menu is visible to this tenant.'
                    example: true
                  language:
                    type: string
                    description: 'Default UI language for the Pbx.'
                    enum:
                      - en
                      - de
                      - fr
                    example: en
                  estimated_users:
                    type: integer
                    format: int32
                    description: 'Estimated number of billable users on this Pbx.'
                    example: 25
                  estimated_sip_devices:
                    type: integer
                    format: int32
                    description: 'Estimated number of billable SIP devices on this Pbx.'
                    example: 30
                  multicast_sites_ip_addresses:
                    type:
                      - array
                      - 'null'
                    description: 'IP addresses of the Mikrotik routers used for multicast paging, or null when none are configured.'
                    items:
                      type: string
                    example:
                      - 10.10.0.1
                      - 10.10.0.2
                  flags:
                    type:
                      - object
                      - 'null'
                    description: 'Free-form feature-flag bag for tenant-specific opt-ins. Null when no flags are set.'
                    additionalProperties: true
                    example:
                      beta_dashboard: true
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the Pbx was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the Pbx was last updated.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  deleted_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the Pbx was soft-deleted, or null if active.'
                    example: null
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                name: 'Acme Corp'
                instance_name: pbx16dev
                partner_id: 550e8400-e29b-41d4-a716-446655440001
                customer_id: 550e8400-e29b-41d4-a716-446655440002
                profile_id: 42
                default_carrier_id: 550e8400-e29b-41d4-a716-446655440003
                fallback_carrier_id: 550e8400-e29b-41d4-a716-446655440004
                default_internal_call_flow_id: 550e8400-e29b-41d4-a716-446655440005
                default_external_call_flow_id: 550e8400-e29b-41d4-a716-446655440006
                no_ext_match_callflow_id: 550e8400-e29b-41d4-a716-446655440007
                default_call_flow_id: 550e8400-e29b-41d4-a716-446655440008
                default_caller_id: '+12125550100'
                music_on_hold_id: 550e8400-e29b-41d4-a716-446655440009
                max_incoming_channels: 50
                max_incoming_channels_sound_file_id: 550e8400-e29b-41d4-a716-446655440000
                trunk_username: trunk_acme
                reserved_extensions: '00, 11'
                emergency: true
                automatic_firmware: true
                default_call_pickups_for_new_extensions: true
                allow_roaming: true
                phones_default_vlan_pc: 200
                phones_default_vlan_phone: 100
                lldp: true
                show_users_first_name_first: true
                capitalize_users_last_name: false
                default_call_ring_duration: 30
                ring_tone: lu
                language: en
                allow_call_recording: true
                allow_changing_record_calls: true
                recordings_destination: mixvoip
                recording_start_at: on_bridge
                transcript_retention_days: 30
                sso_enabled: false
                sso_type: openid_connect
                allow_sign_up_with_sso: false
                force_sign_in_with_sso: false
                sso_identity_fields_mapping:
                  first_name: given_name
                  last_name: family_name
                  email: email
                server_push_date: '2024-03-01T08:29:07Z'
                contact_push_date: '2024-03-01T08:29:07Z'
                push_required: false
                push_check_pending: false
                push_check_requested_at: '2024-03-01T08:29:07Z'
                push_required_count: 0
                push_other_count: 0
                last_config_update: '2024-03-01T08:29:07Z'
                it_admin_notification_email: it@example.com
                ai_engine_status: false
                last_ai_engine_status_activity_check: '2024-03-01T08:29:07Z'
                microsoft365_integration_enabled: false
                microsoft365_admin_consent_status: false
                enable_soop_status: false
                enable_tempus_menu: true
                show_all_users_in_voxbi: true
                show_via_in_missed_call: false
                split_internal_external_calls: false
                call_block_logged_out_sip_devices: false
                estimated_users: 25
                estimated_sip_devices: 30
                multicast_sites_ip_addresses:
                  - 10.10.0.1
                  - 10.10.0.2
                created_at: '2024-03-01T08:29:07Z'
                updated_at: '2024-03-01T08:29:07Z'
                deleted_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /numbers:
    get:
      tags:
        - Numbers
      summary: 'List phone numbers on the PBX'
      operationId: listPbxNumbers
      security:
        -
          IntegrationApiKey: {}
      description: |
        List the PhoneNumbers attached to the caller's PBX (resolved from the bearer
        token). Each entry includes the currently-attached call flow (id + summary)
        when one is configured.

        The list is **paginated** (`data` + `meta` + `links`) and supports filtering
        and sorting.
      parameters:
        -
          in: query
          name: 'filter[number]'
          required: false
          schema:
            type: string
          description: |
            Filter by phone number (substring match). A leading `+` is ignored, so
            `filter[number]=+4922` and `filter[number]=4922` both match.
          example: '4922'
        -
          in: query
          name: 'filter[name]'
          required: false
          schema:
            type: string
          description: "Filter by the number's name (substring match)."
          example: Support
        -
          in: query
          name: sort
          required: false
          schema:
            type: string
            enum:
              - number
              - '-number'
              - name
              - '-name'
              - created_at
              - '-created_at'
          description: |
            Sort field; prefix with `-` for descending. Allowed: `number`, `name`,
            `created_at`. Defaults to `number` ascending.
          example: '-created_at'
        -
          in: query
          name: page
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Page number (1-based).'
          example: 1
        -
          in: query
          name: per_page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: |
            Items per page. Defaults to and is capped at 100 (the API page-length
            limit); larger values are clamped to 100.
          example: 50
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        number:
                          type: string
                          description: 'Phone number in E.164 format.'
                          example: '+12125550100'
                        name:
                          type:
                            - string
                            - 'null'
                          example: 'Customer Support'
                        is_active:
                          type: boolean
                          example: true
                        call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440100
                        call_flow:
                          type:
                            - object
                            - 'null'
                          properties:
                            id:
                              type: string
                              format: uuid
                            name:
                              type: string
                            enabled:
                              type: boolean
                  links:
                    type: object
                    description: 'First/last/prev/next page URLs.'
                  meta:
                    type: object
                    description: 'Pagination metadata (current_page, per_page, total, last_page, ...).'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    number: '+12125550100'
                    name: 'Customer Support'
                    is_active: true
                    call_flow_id: 550e8400-e29b-41d4-a716-446655440100
                    call_flow:
                      id: 550e8400-e29b-41d4-a716-446655440100
                      name: 'Business hours'
                      enabled: true
                links:
                  first: 'https://cockpit.voxbi.com/api/v1/numbers?page=1'
                  last: 'https://cockpit.voxbi.com/api/v1/numbers?page=3'
                  prev: null
                  next: 'https://cockpit.voxbi.com/api/v1/numbers?page=2'
                meta:
                  current_page: 1
                  per_page: 50
                  total: 124
                  last_page: 3
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  '/numbers/{id}/call-flow':
    put:
      tags:
        - Numbers
      summary: 'Attach a call flow to a phone number'
      operationId: updatePbxNumberCallFlow
      security:
        -
          IntegrationApiKey: {}
      description: |
        Set the handling strategy of a PhoneNumber to route incoming calls through
        a specific call flow. Both the PhoneNumber and the CallFlow must belong to
        the caller's PBX.
      parameters:
        -
          in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: 'PhoneNumber UUID.'
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - call_flow_id
              properties:
                call_flow_id:
                  type: string
                  format: uuid
                  example: 550e8400-e29b-41d4-a716-446655440100
      responses:
        200:
          description: 'Updated PhoneNumber with the new call flow attached.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440000
                  number:
                    type: string
                    description: 'Phone number in E.164 format.'
                    example: '+12125550100'
                  name:
                    type:
                      - string
                      - 'null'
                    example: 'Customer Support'
                  is_active:
                    type: boolean
                    example: true
                  call_flow_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440100
                  call_flow:
                    type:
                      - object
                      - 'null'
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                      enabled:
                        type: boolean
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: "PhoneNumber not found in the caller's PBX."
        422:
          description: |
            Validation error - call_flow_id missing, malformed, or doesn't belong
            to the caller's PBX.
  /numbers/orders/check:
    post:
      tags:
        - Numbers
      summary: 'Check whether a phone number can be ordered at a given address'
      operationId: checkPhoneNumberOrder
      security:
        -
          IntegrationApiKey: {}
      description: |
        Pre-flight check that validates an address with the upstream registry and
        returns (a) the dial `prefix` for the resolved location, (b) the geocoder's
        `resolvedAddress`, and (c) the `kycRequirements` that must accompany the
        future order. Call this before `POST /numbers/orders`.

        ### Comparing the address

        The address is geocoded, so `resolvedAddress` may differ from what you sent
        (`address` echoes your input). Compare the two and, if they differ, confirm
        the corrected values with the end user before placing the order - the order
        endpoint persists the geocoder-resolved values. Structured fields in
        `resolvedAddress` are nullable (the geocoder may fail to pin a component such
        as the street number); `formattedAddress` is always present.

        ### Working with `kycRequirements`

        `kycRequirements` lists the KYC documents that must be supplied on
        `POST /numbers/orders`. Each **top-level entry** is either:

          * an **object** - that exact document is required, or
          * an **array of objects** - you must provide **any one** of the documents
            listed inside (an "OR group").

        So the example below requires **two** documents in total:

          * either a `business_registration_certificate` **or** a `utility_bill`
            (the OR group), **and**
          * an `id_document` (the standalone entry).

        Each `documentType` is the code you reference when uploading on
        `POST /numbers/orders`: send file documents as a file part
        `kyc[<documentType>]` (e.g. `kyc[utility_bill]` carrying `bill.pdf`;
        accepted MIME types `application/pdf`, `image/jpeg`, `image/png`), and
        identifier-only documents as a form field
        `kyc[<documentType>]=<value>` (e.g. `kyc[business_registration_number]=BE-12345`).

        The optional `notes` field carries country-specific context (the local name
        of the document, or a freshness constraint such as "dated within 3 months")
        and can be surfaced verbatim to the end user.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - street
                - street_number
                - postal_code
                - city
                - country
              properties:
                street:
                  type: string
                  example: Adenauerallee
                street_number:
                  type: string
                  example: '1'
                postal_code:
                  type: string
                  example: '53113'
                city:
                  type: string
                  example: Bonn
                area_code:
                  type:
                    - string
                    - 'null'
                  maxLength: 16
                  description: |
                    Country-conditional. Required for some countries (e.g. Switzerland,
                    `CH`, where it would be something like `43`) and must be omitted for
                    others - it is `null` for the `DE` example here. Send the same value
                    you will send to `POST /numbers/orders`.
                  example: null
                country:
                  type: string
                  minLength: 2
                  maxLength: 2
                  description: 'ISO 3166-1 alpha-2 country code.'
                  example: DE
      responses:
        200:
          description: 'Address resolved successfully; KYC requirements returned.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  address:
                    type: object
                    description: 'Echo of the address components you submitted.'
                    properties:
                      street:
                        type: string
                        example: Adenauerallee
                      street_number:
                        type: string
                        example: '1'
                      postal_code:
                        type: string
                        example: '53113'
                      city:
                        type: string
                        example: Bonn
                      country:
                        type: string
                        example: DE
                  resolvedAddress:
                    type: object
                    description: |
                      Address as resolved by the geocoder. Compare against `address`
                      to detect corrections. Structured fields are nullable;
                      `formattedAddress` is always present.
                    properties:
                      street:
                        type:
                          - string
                          - 'null'
                        example: Adenauerallee
                      streetNumber:
                        type:
                          - string
                          - 'null'
                        example: '1'
                      postalCode:
                        type:
                          - string
                          - 'null'
                        example: '53113'
                      city:
                        type:
                          - string
                          - 'null'
                        example: Bonn
                      country:
                        type:
                          - string
                          - 'null'
                        example: DE
                      formattedAddress:
                        type: string
                        description: 'Human-readable resolved address. Always present.'
                        example: 'Adenauerallee 1, 53113 Bonn, Germany'
                  prefix:
                    type: string
                    description: |
                      Dial prefix for the resolved location in E.164 form with a
                      leading `+` (country prefix plus area code where applicable).
                    example: '+49228'
                  kycRequirements:
                    type: array
                    description: |
                      KYC documents required on the future order. Each entry is
                      either a single requirement object, or an array of objects
                      meaning "provide any one of these". See the endpoint
                      description for how to upload each `documentType`.
                    items:
                      oneOf:
                        -
                          type: object
                          required:
                            - documentType
                          properties:
                            documentType:
                              type: string
                              description: |
                                The KYC document type code. Reference it when uploading the document on
                                `POST /numbers/orders` as `kyc[<documentType>]` (a file part for document
                                types, or a form-field value for identifier-only types such as
                                `business_registration_number`).
                              enum:
                                - business_registration_certificate
                                - utility_bill
                                - id_document
                                - business_registration_number
                              example: utility_bill
                            notes:
                              type:
                                - string
                                - 'null'
                              description: |
                                Country-specific context - the local name of the document or a freshness
                                constraint. Safe to surface verbatim to the end user.
                              example: 'Dated within 3 months'
                        -
                          type: array
                          items:
                            type: object
                            required:
                              - documentType
                            properties:
                              documentType:
                                type: string
                                description: |
                                  The KYC document type code. Reference it when uploading the document on
                                  `POST /numbers/orders` as `kyc[<documentType>]` (a file part for document
                                  types, or a form-field value for identifier-only types such as
                                  `business_registration_number`).
                                enum:
                                  - business_registration_certificate
                                  - utility_bill
                                  - id_document
                                  - business_registration_number
                                example: utility_bill
                              notes:
                                type:
                                  - string
                                  - 'null'
                                description: |
                                  Country-specific context - the local name of the document or a freshness
                                  constraint. Safe to surface verbatim to the end user.
                                example: 'Dated within 3 months'
              example:
                address:
                  street: Adenauerallee
                  street_number: '1'
                  postal_code: '53113'
                  city: Bonn
                  country: DE
                resolvedAddress:
                  street: Adenauerallee
                  streetNumber: '1'
                  postalCode: '53113'
                  city: Bonn
                  country: DE
                  formattedAddress: 'Adenauerallee 1, 53113 Bonn, Germany'
                prefix: '+49228'
                kycRequirements:
                  -
                    -
                      documentType: business_registration_certificate
                      notes: Handelsregister
                    -
                      documentType: utility_bill
                      notes: 'Dated within 3 months'
                  -
                    documentType: id_document
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: |
            The address failed validation - locally or upstream (e.g. it could not be
            resolved, or your account may not order numbers for that country). Same
            `{ message, errors }` shape as every other API validation 422, with
            `errors` mapping each rejected field to its messages. No order is created
            at this stage, so there is no `data`.

            When an upstream error has no field to attach to, `errors` is an empty
            object `{}` and `message` carries the reason.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - errors
                additionalProperties: false
                properties:
                  message:
                    type: string
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
              examples:
                validationError:
                  summary: 'Local validation - one or more fields invalid'
                  value:
                    message: 'The street field is required. (and 1 more error)'
                    errors:
                      street:
                        - 'The street field is required.'
                      street_number:
                        - 'The street number field is required.'
                countryNotAllowed:
                  summary: 'Account not authorised to order in this country'
                  value:
                    message: 'Phone numbers cannot be ordered for this country. Your account is not authorised to order numbers here - pick a different country or contact support.'
                    errors:
                      country:
                        - 'Phone numbers cannot be ordered for this country. Your account is not authorised to order numbers here - pick a different country or contact support.'
  /numbers/orders:
    post:
      tags:
        - Numbers
      summary: 'Place a phone number order'
      operationId: createPhoneNumberOrder
      security:
        -
          IntegrationApiKey: {}
      description: |
        Submit a phone number order. Must be called as `multipart/form-data` because
        KYC document files are part of the request. Call `POST /numbers/orders/check`
        first to obtain the address-specific `kycRequirements`.

        You may attach your own `order_id` (any short string, max 64 chars) - it
        will be echoed back to you in the response, in `GET /numbers/orders/{id}`,
        and in the asynchronous webhook payload below. If you omit it, the upstream
        provider will generate one and we'll backfill it on your row.

        Order fulfilment is asynchronous. This endpoint returns `201` as soon as the
        order is accepted upstream. The final outcome (success or rejection) will be
        delivered to your `webhook` URL (if provided) and is queryable via
        `GET /numbers/orders/{id}`.

        ### Webhook payload

        When the order reaches its final state we POST to your `webhook` URL the
        **exact same body** as `GET /numbers/orders/{id}` (the schema below). Read
        the `status` field to tell success from rejection:

          * `status: "success"` - `numbers` and `phone_numbers` are populated.
          * `status: "error"` - `error_message` carries the rejection reason.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - customer_name
                - street
                - street_number
                - postal_code
                - city
                - country
                - quantity
              properties:
                customer_name:
                  type: string
                  maxLength: 255
                  description: |
                    Legal name of the customer the numbers are ordered for. Required;
                    forwarded to the carrier, which records and may validate it.
                  example: 'ACME GmbH'
                street:
                  type: string
                  example: Adenauerallee
                street_number:
                  type: string
                  example: '1'
                postal_code:
                  type: string
                  example: '53113'
                city:
                  type: string
                  example: Bonn
                area_code:
                  type:
                    - string
                    - 'null'
                  maxLength: 16
                  description: |
                    Country-conditional. Required for some countries (e.g. Switzerland,
                    `CH`, where it would be something like `43`) and rejected (422) for
                    others - it is `null` for the `DE` example here. Use the same value
                    you sent to `POST /numbers/orders/check`.
                  example: null
                country:
                  type: string
                  example: DE
                quantity:
                  type: integer
                  minimum: 1
                  example: 1
                webhook:
                  type:
                    - string
                    - 'null'
                  format: uri
                  description: |
                    Optional URL we POST to once the order is fulfilled. The order is
                    accepted asynchronously (this endpoint returns `201` with status
                    `requested`), so the assigned numbers - or a rejection - are
                    delivered here later, not in this response. See "Webhook payloads"
                    above for the exact body. The same outcome can also be fetched from
                    `GET /numbers/orders/{id}`.
                  maxLength: 500
                  example: 'https://your-app.example/hooks/number-order'
                order_id:
                  type:
                    - string
                    - 'null'
                  maxLength: 64
                  description: |
                    Optional customer reference (any short string, max 64 chars).
                    Echoed back in the response, in `GET /numbers/orders/{id}`, and
                    at the top level of the asynchronous webhook payload as
                    `order_id` (the webhook body is the same order object). If
                    omitted, the upstream provider generates one and we backfill it
                    on your row.
                  example: po-2026-00042
                kyc:
                  type: object
                  additionalProperties: true
                  description: |
                    KYC documents, one entry per `documentType` returned by
                    `POST /numbers/orders/check` for the country. Send file documents
                    as a file part `kyc[<documentType>]` and identifier-only documents
                    as a form field `kyc[<documentType>]=<value>`. Accepted file MIME
                    types: `application/pdf`, `image/jpeg`, `image/png`. Example shape:

                      * `kyc[utility_bill]` - file part carrying `bill.pdf`
                      * `kyc[id_document]` - file part carrying `passport.jpg`
                      * `kyc[business_registration_number]=BE-12345` - form field

                    For an OR group returned by the check endpoint (an array of types),
                    provide any one of the listed `documentType`s.
      responses:
        201:
          description: 'Order accepted upstream and persisted on our side.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: |
                      Internal order id assigned by us. Use this with `GET /numbers/orders/{id}`
                      to fetch the latest state. NOT the value echoed in the asynchronous
                      webhook payload - that one is `order_id` (your own reference).
                    example: 550e8400-e29b-41d4-a716-446655440000
                  order_id:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: |
                      Your customer reference, supplied via the `order_id` field in
                      `POST /numbers/orders` (or `POST /numbers/orders/{id}`). Echoed back here,
                      in `GET /numbers/orders/{id}`, and at the top level of the asynchronous
                      webhook payload (which is this same object) as `order_id`.
                    example: po-2026-00042
                  customer_name:
                    type: string
                    description: |
                      Legal name of the customer the numbers were ordered for, as supplied on
                      create (and editable on retry).
                    example: 'ACME GmbH'
                  status:
                    type: string
                    enum:
                      - created
                      - requested
                      - submission_failed
                      - processing
                      - success
                      - error
                      - processing_failed
                    description: |
                      Lifecycle state of this order.
                       * `requested`: sent upstream, awaiting fulfilment.
                       * `submission_failed`: rejected during synchronous submission; editable + retryable.
                       * `processing`: async success callback received; provisioning in progress.
                       * `success`: provisioning complete; `numbers` is populated.
                       * `error`: async rejection; terminal.
                       * `processing_failed`: internal processing exhausted retries; admin-only retry.
                    example: requested
                  address:
                    type: object
                    properties:
                      street:
                        type: string
                        example: Adenauerallee
                      street_number:
                        type: string
                        example: '1'
                      postal_code:
                        type: string
                        example: '53113'
                      city:
                        type: string
                        example: Bonn
                      area_code:
                        type:
                          - string
                          - 'null'
                        description: 'Country-conditional (e.g. set for CH); null otherwise.'
                        example: null
                      country:
                        type: string
                        example: DE
                  formatted_address:
                    type:
                      - string
                      - 'null'
                    description: |
                      Single-line, comma-separated address derived from the persisted
                      components (street + number, postal code + city, country). Empty
                      components are dropped.
                    example: 'Adenauerallee 1, 53113 Bonn, DE'
                  quantity:
                    type: integer
                    example: 1
                  prefix:
                    type:
                      - string
                      - 'null'
                    description: 'Dial prefix in E.164 (country + area code if applicable).'
                    example: '+49228'
                  numbers:
                    type: array
                    description: |
                      E.164-formatted numbers assigned to this order. Empty (`[]`) until the
                      order reaches `success` - they are never returned synchronously by
                      `POST /numbers/orders` (which only ever returns `requested`); they arrive
                      later via the webhook and then appear here on `GET /numbers/orders/{id}`.
                    items:
                      type: string
                    example:
                      - '+4922812345678'
                  phone_numbers:
                    type: array
                    description: |
                      The assigned numbers, in the same shape as `GET /numbers`
                      (id, number, name, is_active, call_flow), so you can read each number's id
                      and current call flow and act on it directly (e.g. `PUT /numbers/{id}/call-flow`).
                      Populated once the order reaches `success`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        number:
                          type: string
                          description: 'Phone number in E.164 format.'
                          example: '+12125550100'
                        name:
                          type:
                            - string
                            - 'null'
                          example: 'Customer Support'
                        is_active:
                          type: boolean
                          example: true
                        call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440100
                        call_flow:
                          type:
                            - object
                            - 'null'
                          properties:
                            id:
                              type: string
                              format: uuid
                            name:
                              type: string
                            enabled:
                              type: boolean
                  error_message:
                    type:
                      - string
                      - 'null'
                    description: 'Short error reason when status is `error` or `submission_failed`.'
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    description: 'The webhook URL we will POST the final outcome to.'
                  webhook_status:
                    type: string
                    enum:
                      - not_required
                      - pending
                      - retrying
                      - delivered
                      - failed
                      - cancelled
                  webhook_next_retry_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                order_id: po-2026-00042
                customer_name: 'ACME GmbH'
                status: requested
                address:
                  street: Adenauerallee
                  street_number: '1'
                  postal_code: '53113'
                  city: Bonn
                  area_code: null
                  country: DE
                formatted_address: 'Adenauerallee 1, 53113 Bonn, DE'
                quantity: 1
                prefix: '+49228'
                numbers: {}
                phone_numbers: {}
                error_message: null
                webhook_url: 'https://your-app.example/hooks/number-order'
                webhook_status: pending
                webhook_next_retry_at: null
                created_at: '2026-05-12T10:36:47+00:00'
                updated_at: '2026-05-12T10:36:47+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: |
            Validation failed. `errors` maps each rejected field to its messages.

            If the order reached the carrier and was rejected there, it is persisted
            as a retryable `submission_failed` order and returned in `data` (the full
            order, same shape as `GET /numbers/orders/{id}`); use `data.id` to edit +
            retry it via `POST /numbers/orders/{id}`. When `data` is absent, no order
            was created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - errors
                additionalProperties: false
                properties:
                  message:
                    type: string
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                  data:
                    description: |
                      Present only for a carrier rejection (a retryable order was
                      persisted). The full order - same shape as
                      `GET /numbers/orders/{id}` - whose `id` you pass to
                      `POST /numbers/orders/{id}` to edit + retry. Absent for local
                      validation errors.
                    allOf:
                      -
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                            description: |
                              Internal order id assigned by us. Use this with `GET /numbers/orders/{id}`
                              to fetch the latest state. NOT the value echoed in the asynchronous
                              webhook payload - that one is `order_id` (your own reference).
                            example: 550e8400-e29b-41d4-a716-446655440000
                          order_id:
                            type:
                              - string
                              - 'null'
                            maxLength: 64
                            description: |
                              Your customer reference, supplied via the `order_id` field in
                              `POST /numbers/orders` (or `POST /numbers/orders/{id}`). Echoed back here,
                              in `GET /numbers/orders/{id}`, and at the top level of the asynchronous
                              webhook payload (which is this same object) as `order_id`.
                            example: po-2026-00042
                          customer_name:
                            type: string
                            description: |
                              Legal name of the customer the numbers were ordered for, as supplied on
                              create (and editable on retry).
                            example: 'ACME GmbH'
                          status:
                            type: string
                            enum:
                              - created
                              - requested
                              - submission_failed
                              - processing
                              - success
                              - error
                              - processing_failed
                            description: |
                              Lifecycle state of this order.
                               * `requested`: sent upstream, awaiting fulfilment.
                               * `submission_failed`: rejected during synchronous submission; editable + retryable.
                               * `processing`: async success callback received; provisioning in progress.
                               * `success`: provisioning complete; `numbers` is populated.
                               * `error`: async rejection; terminal.
                               * `processing_failed`: internal processing exhausted retries; admin-only retry.
                            example: requested
                          address:
                            type: object
                            properties:
                              street:
                                type: string
                                example: Adenauerallee
                              street_number:
                                type: string
                                example: '1'
                              postal_code:
                                type: string
                                example: '53113'
                              city:
                                type: string
                                example: Bonn
                              area_code:
                                type:
                                  - string
                                  - 'null'
                                description: 'Country-conditional (e.g. set for CH); null otherwise.'
                                example: null
                              country:
                                type: string
                                example: DE
                          formatted_address:
                            type:
                              - string
                              - 'null'
                            description: |
                              Single-line, comma-separated address derived from the persisted
                              components (street + number, postal code + city, country). Empty
                              components are dropped.
                            example: 'Adenauerallee 1, 53113 Bonn, DE'
                          quantity:
                            type: integer
                            example: 1
                          prefix:
                            type:
                              - string
                              - 'null'
                            description: 'Dial prefix in E.164 (country + area code if applicable).'
                            example: '+49228'
                          numbers:
                            type: array
                            description: |
                              E.164-formatted numbers assigned to this order. Empty (`[]`) until the
                              order reaches `success` - they are never returned synchronously by
                              `POST /numbers/orders` (which only ever returns `requested`); they arrive
                              later via the webhook and then appear here on `GET /numbers/orders/{id}`.
                            items:
                              type: string
                            example:
                              - '+4922812345678'
                          phone_numbers:
                            type: array
                            description: |
                              The assigned numbers, in the same shape as `GET /numbers`
                              (id, number, name, is_active, call_flow), so you can read each number's id
                              and current call flow and act on it directly (e.g. `PUT /numbers/{id}/call-flow`).
                              Populated once the order reaches `success`.
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                  example: 550e8400-e29b-41d4-a716-446655440000
                                number:
                                  type: string
                                  description: 'Phone number in E.164 format.'
                                  example: '+12125550100'
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Customer Support'
                                is_active:
                                  type: boolean
                                  example: true
                                call_flow_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  example: 550e8400-e29b-41d4-a716-446655440100
                                call_flow:
                                  type:
                                    - object
                                    - 'null'
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                    name:
                                      type: string
                                    enabled:
                                      type: boolean
                          error_message:
                            type:
                              - string
                              - 'null'
                            description: 'Short error reason when status is `error` or `submission_failed`.'
                          webhook_url:
                            type:
                              - string
                              - 'null'
                            description: 'The webhook URL we will POST the final outcome to.'
                          webhook_status:
                            type: string
                            enum:
                              - not_required
                              - pending
                              - retrying
                              - delivered
                              - failed
                              - cancelled
                          webhook_next_retry_at:
                            type:
                              - string
                              - 'null'
                            format: date-time
                          created_at:
                            type: string
                            format: date-time
                          updated_at:
                            type: string
                            format: date-time
              examples:
                validationError:
                  summary: 'Local validation - one or more fields invalid'
                  value:
                    message: 'The customer name field is required. (and 9 more errors)'
                    errors:
                      customer_name:
                        - 'The customer name field is required.'
                      street:
                        - 'The street field is required.'
                      street_number:
                        - 'The street number field is required.'
                      postal_code:
                        - 'The postal code field is required.'
                      city:
                        - 'The city field is required.'
                      country:
                        - 'The country field is required.'
                      area_code:
                        - 'The area code field is required.'
                      quantity:
                        - 'The quantity field must be at least 1.'
                      webhook:
                        - 'The webhook field must be a valid URL.'
                      order_id:
                        - 'The order id field must not be greater than 64 characters.'
                carrierRejection:
                  summary: 'Carrier rejected the order (mapped to your fields)'
                  value:
                    message: 'This value is too short. It should have 3 characters or more. (and 1 more error)'
                    errors:
                      customer_name:
                        - 'This value is too short. It should have 3 characters or more.'
                      city:
                        - 'The city does not match the provided postal code.'
                    data:
                      id: 550e8400-e29b-41d4-a716-446655440000
                      order_id: po-2026-00042
                      customer_name: 'ACME GmbH'
                      status: submission_failed
                      address:
                        street: Adenauerallee
                        street_number: '1'
                        postal_code: '53113'
                        city: Bonn
                        area_code: null
                        country: DE
                      formatted_address: 'Adenauerallee 1, 53113 Bonn, DE'
                      quantity: 1
                      prefix: null
                      numbers: {}
                      phone_numbers: {}
                      error_message: 'Nexus rejected the request with status 422'
                      webhook_url: 'https://your-app.example/hooks/number-order'
                      webhook_status: not_required
                      webhook_next_retry_at: null
                      created_at: '2026-05-12T10:36:47+00:00'
                      updated_at: '2026-05-12T10:36:47+00:00'
  '/numbers/orders/{id}':
    get:
      tags:
        - Numbers
      summary: 'Get a phone number order'
      operationId: getPhoneNumberOrder
      security:
        -
          IntegrationApiKey: {}
      description: |
        Retrieve the current state of a phone number order. The order outcome
        (assigned numbers on success, or the rejection reason) can be fetched here
        if you cannot accept the webhook callback, and it also lets you inspect a
        past order's audit trail.
      parameters:
        -
          in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: 'Order UUID returned by `POST /numbers/orders`.'
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: |
                      Internal order id assigned by us. Use this with `GET /numbers/orders/{id}`
                      to fetch the latest state. NOT the value echoed in the asynchronous
                      webhook payload - that one is `order_id` (your own reference).
                    example: 550e8400-e29b-41d4-a716-446655440000
                  order_id:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: |
                      Your customer reference, supplied via the `order_id` field in
                      `POST /numbers/orders` (or `POST /numbers/orders/{id}`). Echoed back here,
                      in `GET /numbers/orders/{id}`, and at the top level of the asynchronous
                      webhook payload (which is this same object) as `order_id`.
                    example: po-2026-00042
                  customer_name:
                    type: string
                    description: |
                      Legal name of the customer the numbers were ordered for, as supplied on
                      create (and editable on retry).
                    example: 'ACME GmbH'
                  status:
                    type: string
                    enum:
                      - created
                      - requested
                      - submission_failed
                      - processing
                      - success
                      - error
                      - processing_failed
                    description: |
                      Lifecycle state of this order.
                       * `requested`: sent upstream, awaiting fulfilment.
                       * `submission_failed`: rejected during synchronous submission; editable + retryable.
                       * `processing`: async success callback received; provisioning in progress.
                       * `success`: provisioning complete; `numbers` is populated.
                       * `error`: async rejection; terminal.
                       * `processing_failed`: internal processing exhausted retries; admin-only retry.
                    example: requested
                  address:
                    type: object
                    properties:
                      street:
                        type: string
                        example: Adenauerallee
                      street_number:
                        type: string
                        example: '1'
                      postal_code:
                        type: string
                        example: '53113'
                      city:
                        type: string
                        example: Bonn
                      area_code:
                        type:
                          - string
                          - 'null'
                        description: 'Country-conditional (e.g. set for CH); null otherwise.'
                        example: null
                      country:
                        type: string
                        example: DE
                  formatted_address:
                    type:
                      - string
                      - 'null'
                    description: |
                      Single-line, comma-separated address derived from the persisted
                      components (street + number, postal code + city, country). Empty
                      components are dropped.
                    example: 'Adenauerallee 1, 53113 Bonn, DE'
                  quantity:
                    type: integer
                    example: 1
                  prefix:
                    type:
                      - string
                      - 'null'
                    description: 'Dial prefix in E.164 (country + area code if applicable).'
                    example: '+49228'
                  numbers:
                    type: array
                    description: |
                      E.164-formatted numbers assigned to this order. Empty (`[]`) until the
                      order reaches `success` - they are never returned synchronously by
                      `POST /numbers/orders` (which only ever returns `requested`); they arrive
                      later via the webhook and then appear here on `GET /numbers/orders/{id}`.
                    items:
                      type: string
                    example:
                      - '+4922812345678'
                  phone_numbers:
                    type: array
                    description: |
                      The assigned numbers, in the same shape as `GET /numbers`
                      (id, number, name, is_active, call_flow), so you can read each number's id
                      and current call flow and act on it directly (e.g. `PUT /numbers/{id}/call-flow`).
                      Populated once the order reaches `success`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        number:
                          type: string
                          description: 'Phone number in E.164 format.'
                          example: '+12125550100'
                        name:
                          type:
                            - string
                            - 'null'
                          example: 'Customer Support'
                        is_active:
                          type: boolean
                          example: true
                        call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440100
                        call_flow:
                          type:
                            - object
                            - 'null'
                          properties:
                            id:
                              type: string
                              format: uuid
                            name:
                              type: string
                            enabled:
                              type: boolean
                  error_message:
                    type:
                      - string
                      - 'null'
                    description: 'Short error reason when status is `error` or `submission_failed`.'
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    description: 'The webhook URL we will POST the final outcome to.'
                  webhook_status:
                    type: string
                    enum:
                      - not_required
                      - pending
                      - retrying
                      - delivered
                      - failed
                      - cancelled
                  webhook_next_retry_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: "Order not found in the caller's PBX."
    post:
      tags:
        - Numbers
      summary: 'Edit and retry a failed phone number order'
      operationId: updatePhoneNumberOrder
      security:
        -
          IntegrationApiKey: {}
      description: |
        Edit selected fields of a `submission_failed` order and re-submit it
        upstream. Same multipart contract as `POST /numbers/orders`.

        Uses `POST` (not `PUT`) on purpose: the body is `multipart/form-data`, and
        many server runtimes only parse a multipart body when the method is `POST` -
        on `PUT` the fields and files arrive empty. Send this edit as a plain `POST`.

        Constraints:
        - Only orders with status `submission_failed` can be edited.
        - `country` is frozen. You may re-send it with the same value (handy when
          you echo back the whole order), but *changing* it returns `422` - order in
          a different country by creating a new order. Omitting it is also fine.

        `customer_name` and `order_id` are editable here: send new values to change
        them, or send an empty `order_id` to clear your reference.

        If the edited address yields different KYC requirements upstream, the
        response will be `422` carrying the new requirements; resubmit again with
        the matching KYC fields.
      parameters:
        -
          in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - customer_name
                - street
                - street_number
                - postal_code
                - city
                - quantity
              properties:
                customer_name:
                  type: string
                  maxLength: 255
                  description: |
                    Legal name of the customer. Required and editable on retry;
                    forwarded to the carrier, which may validate it.
                  example: 'ACME GmbH'
                street:
                  type: string
                street_number:
                  type: string
                postal_code:
                  type: string
                city:
                  type: string
                area_code:
                  type:
                    - string
                    - 'null'
                  maxLength: 16
                  description: |
                    Country-conditional. Required when the order's (locked) country
                    needs it - e.g. Switzerland (`CH`), where it would be something like
                    `43` - and rejected (422) otherwise.
                  example: null
                quantity:
                  type: integer
                  minimum: 1
                webhook:
                  type:
                    - string
                    - 'null'
                  format: uri
                order_id:
                  type:
                    - string
                    - 'null'
                  maxLength: 64
                  description: |
                    Optional customer reference (max 64 chars). Editable on retry -
                    send a new value to change it, or an empty string to clear it.
                    Echoed back in the response, in `GET /numbers/orders/{id}`, and
                    at the top level of the asynchronous webhook payload as `order_id`
                    (the webhook body is the same order object).
                  example: po-2026-00042
                kyc:
                  type: object
                  additionalProperties: true
                  description: |
                    KYC documents, one entry per `documentType` returned by
                    `POST /numbers/orders/check` for the country. Send file documents
                    as a file part `kyc[<documentType>]` and identifier-only documents
                    as a form field `kyc[<documentType>]=<value>`. Accepted file MIME
                    types: `application/pdf`, `image/jpeg`, `image/png`. Example shape:

                      * `kyc[utility_bill]` - file part carrying `bill.pdf`
                      * `kyc[id_document]` - file part carrying `passport.jpg`
                      * `kyc[business_registration_number]=BE-12345` - form field

                    For an OR group returned by the check endpoint (an array of types),
                    provide any one of the listed `documentType`s. Re-send the KYC
                    documents you want on the retried order; on submission_failed
                    retries the carrier re-validates them.
      responses:
        200:
          description: 'Order re-submitted upstream successfully.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: |
                      Internal order id assigned by us. Use this with `GET /numbers/orders/{id}`
                      to fetch the latest state. NOT the value echoed in the asynchronous
                      webhook payload - that one is `order_id` (your own reference).
                    example: 550e8400-e29b-41d4-a716-446655440000
                  order_id:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: |
                      Your customer reference, supplied via the `order_id` field in
                      `POST /numbers/orders` (or `POST /numbers/orders/{id}`). Echoed back here,
                      in `GET /numbers/orders/{id}`, and at the top level of the asynchronous
                      webhook payload (which is this same object) as `order_id`.
                    example: po-2026-00042
                  customer_name:
                    type: string
                    description: |
                      Legal name of the customer the numbers were ordered for, as supplied on
                      create (and editable on retry).
                    example: 'ACME GmbH'
                  status:
                    type: string
                    enum:
                      - created
                      - requested
                      - submission_failed
                      - processing
                      - success
                      - error
                      - processing_failed
                    description: |
                      Lifecycle state of this order.
                       * `requested`: sent upstream, awaiting fulfilment.
                       * `submission_failed`: rejected during synchronous submission; editable + retryable.
                       * `processing`: async success callback received; provisioning in progress.
                       * `success`: provisioning complete; `numbers` is populated.
                       * `error`: async rejection; terminal.
                       * `processing_failed`: internal processing exhausted retries; admin-only retry.
                    example: requested
                  address:
                    type: object
                    properties:
                      street:
                        type: string
                        example: Adenauerallee
                      street_number:
                        type: string
                        example: '1'
                      postal_code:
                        type: string
                        example: '53113'
                      city:
                        type: string
                        example: Bonn
                      area_code:
                        type:
                          - string
                          - 'null'
                        description: 'Country-conditional (e.g. set for CH); null otherwise.'
                        example: null
                      country:
                        type: string
                        example: DE
                  formatted_address:
                    type:
                      - string
                      - 'null'
                    description: |
                      Single-line, comma-separated address derived from the persisted
                      components (street + number, postal code + city, country). Empty
                      components are dropped.
                    example: 'Adenauerallee 1, 53113 Bonn, DE'
                  quantity:
                    type: integer
                    example: 1
                  prefix:
                    type:
                      - string
                      - 'null'
                    description: 'Dial prefix in E.164 (country + area code if applicable).'
                    example: '+49228'
                  numbers:
                    type: array
                    description: |
                      E.164-formatted numbers assigned to this order. Empty (`[]`) until the
                      order reaches `success` - they are never returned synchronously by
                      `POST /numbers/orders` (which only ever returns `requested`); they arrive
                      later via the webhook and then appear here on `GET /numbers/orders/{id}`.
                    items:
                      type: string
                    example:
                      - '+4922812345678'
                  phone_numbers:
                    type: array
                    description: |
                      The assigned numbers, in the same shape as `GET /numbers`
                      (id, number, name, is_active, call_flow), so you can read each number's id
                      and current call flow and act on it directly (e.g. `PUT /numbers/{id}/call-flow`).
                      Populated once the order reaches `success`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        number:
                          type: string
                          description: 'Phone number in E.164 format.'
                          example: '+12125550100'
                        name:
                          type:
                            - string
                            - 'null'
                          example: 'Customer Support'
                        is_active:
                          type: boolean
                          example: true
                        call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440100
                        call_flow:
                          type:
                            - object
                            - 'null'
                          properties:
                            id:
                              type: string
                              format: uuid
                            name:
                              type: string
                            enabled:
                              type: boolean
                  error_message:
                    type:
                      - string
                      - 'null'
                    description: 'Short error reason when status is `error` or `submission_failed`.'
                  webhook_url:
                    type:
                      - string
                      - 'null'
                    description: 'The webhook URL we will POST the final outcome to.'
                  webhook_status:
                    type: string
                    enum:
                      - not_required
                      - pending
                      - retrying
                      - delivered
                      - failed
                      - cancelled
                  webhook_next_retry_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The order was created from a different source (e.g. the Cockpit UI) and
            cannot be retried via the API. Not field-specific, so the body is just a
            `message`.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                additionalProperties: false
                properties:
                  message:
                    type: string
              example:
                message: 'This order was not created via the API; retries must be initiated from the Cockpit UI.'
        404:
          description: "Order not found in the caller's PBX."
        409:
          description: |
            The order is not in `submission_failed` state, so it cannot be edited or
            retried. Not field-specific, so the body is just a `message` (the current
            status is included in it).
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                additionalProperties: false
                properties:
                  message:
                    type: string
              example:
                message: 'Only orders with status submission_failed can be edited and retried (current status: requested).'
        422:
          description: |
            Validation failed. `errors` maps each rejected field to its messages
            (including an attempt to *change* the locked `country`).

            If the carrier rejected the retried order, it stays as a retryable
            `submission_failed` order and is returned in `data` (the full order, same
            shape as `GET /numbers/orders/{id}`); use `data.id` to edit + retry it via
            `POST /numbers/orders/{id}`. When `data` is absent, the failure was local
            validation only.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - errors
                additionalProperties: false
                properties:
                  message:
                    type: string
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                  data:
                    description: |
                      Present only for a carrier rejection (a retryable order was
                      persisted). The full order - same shape as
                      `GET /numbers/orders/{id}` - whose `id` you pass to
                      `POST /numbers/orders/{id}` to edit + retry. Absent for local
                      validation errors.
                    allOf:
                      -
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                            description: |
                              Internal order id assigned by us. Use this with `GET /numbers/orders/{id}`
                              to fetch the latest state. NOT the value echoed in the asynchronous
                              webhook payload - that one is `order_id` (your own reference).
                            example: 550e8400-e29b-41d4-a716-446655440000
                          order_id:
                            type:
                              - string
                              - 'null'
                            maxLength: 64
                            description: |
                              Your customer reference, supplied via the `order_id` field in
                              `POST /numbers/orders` (or `POST /numbers/orders/{id}`). Echoed back here,
                              in `GET /numbers/orders/{id}`, and at the top level of the asynchronous
                              webhook payload (which is this same object) as `order_id`.
                            example: po-2026-00042
                          customer_name:
                            type: string
                            description: |
                              Legal name of the customer the numbers were ordered for, as supplied on
                              create (and editable on retry).
                            example: 'ACME GmbH'
                          status:
                            type: string
                            enum:
                              - created
                              - requested
                              - submission_failed
                              - processing
                              - success
                              - error
                              - processing_failed
                            description: |
                              Lifecycle state of this order.
                               * `requested`: sent upstream, awaiting fulfilment.
                               * `submission_failed`: rejected during synchronous submission; editable + retryable.
                               * `processing`: async success callback received; provisioning in progress.
                               * `success`: provisioning complete; `numbers` is populated.
                               * `error`: async rejection; terminal.
                               * `processing_failed`: internal processing exhausted retries; admin-only retry.
                            example: requested
                          address:
                            type: object
                            properties:
                              street:
                                type: string
                                example: Adenauerallee
                              street_number:
                                type: string
                                example: '1'
                              postal_code:
                                type: string
                                example: '53113'
                              city:
                                type: string
                                example: Bonn
                              area_code:
                                type:
                                  - string
                                  - 'null'
                                description: 'Country-conditional (e.g. set for CH); null otherwise.'
                                example: null
                              country:
                                type: string
                                example: DE
                          formatted_address:
                            type:
                              - string
                              - 'null'
                            description: |
                              Single-line, comma-separated address derived from the persisted
                              components (street + number, postal code + city, country). Empty
                              components are dropped.
                            example: 'Adenauerallee 1, 53113 Bonn, DE'
                          quantity:
                            type: integer
                            example: 1
                          prefix:
                            type:
                              - string
                              - 'null'
                            description: 'Dial prefix in E.164 (country + area code if applicable).'
                            example: '+49228'
                          numbers:
                            type: array
                            description: |
                              E.164-formatted numbers assigned to this order. Empty (`[]`) until the
                              order reaches `success` - they are never returned synchronously by
                              `POST /numbers/orders` (which only ever returns `requested`); they arrive
                              later via the webhook and then appear here on `GET /numbers/orders/{id}`.
                            items:
                              type: string
                            example:
                              - '+4922812345678'
                          phone_numbers:
                            type: array
                            description: |
                              The assigned numbers, in the same shape as `GET /numbers`
                              (id, number, name, is_active, call_flow), so you can read each number's id
                              and current call flow and act on it directly (e.g. `PUT /numbers/{id}/call-flow`).
                              Populated once the order reaches `success`.
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                  example: 550e8400-e29b-41d4-a716-446655440000
                                number:
                                  type: string
                                  description: 'Phone number in E.164 format.'
                                  example: '+12125550100'
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Customer Support'
                                is_active:
                                  type: boolean
                                  example: true
                                call_flow_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  example: 550e8400-e29b-41d4-a716-446655440100
                                call_flow:
                                  type:
                                    - object
                                    - 'null'
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                    name:
                                      type: string
                                    enabled:
                                      type: boolean
                          error_message:
                            type:
                              - string
                              - 'null'
                            description: 'Short error reason when status is `error` or `submission_failed`.'
                          webhook_url:
                            type:
                              - string
                              - 'null'
                            description: 'The webhook URL we will POST the final outcome to.'
                          webhook_status:
                            type: string
                            enum:
                              - not_required
                              - pending
                              - retrying
                              - delivered
                              - failed
                              - cancelled
                          webhook_next_retry_at:
                            type:
                              - string
                              - 'null'
                            format: date-time
                          created_at:
                            type: string
                            format: date-time
                          updated_at:
                            type: string
                            format: date-time
              examples:
                validationError:
                  summary: 'Local validation - one or more fields invalid'
                  value:
                    message: 'The street field is required. (and 4 more errors)'
                    errors:
                      customer_name:
                        - 'The customer name field is required.'
                      street:
                        - 'The street field is required.'
                      street_number:
                        - 'The street number field is required.'
                      postal_code:
                        - 'The postal code field is required.'
                      city:
                        - 'The city field is required.'
                      area_code:
                        - 'The area code field is required.'
                      quantity:
                        - 'The quantity field must be at least 1.'
                      country:
                        - 'Country cannot be changed - create a new request if you need to order in a different country.'
                      order_id:
                        - 'The order id field must not be greater than 64 characters.'
                carrierRejection:
                  summary: 'Carrier rejected the retried order (mapped to your fields)'
                  value:
                    message: 'This value is too short. It should have 3 characters or more. (and 1 more error)'
                    errors:
                      customer_name:
                        - 'This value is too short. It should have 3 characters or more.'
                      city:
                        - 'The city does not match the provided postal code.'
                    data:
                      id: 550e8400-e29b-41d4-a716-446655440000
                      order_id: po-2026-00042
                      customer_name: 'ACME GmbH'
                      status: submission_failed
                      address:
                        street: Adenauerallee
                        street_number: '1'
                        postal_code: '53113'
                        city: Bonn
                        area_code: null
                        country: DE
                      formatted_address: 'Adenauerallee 1, 53113 Bonn, DE'
                      quantity: 1
                      prefix: null
                      numbers: {}
                      phone_numbers: {}
                      error_message: 'Nexus rejected the request with status 422'
                      webhook_url: 'https://your-app.example/hooks/number-order'
                      webhook_status: not_required
                      webhook_next_retry_at: null
                      created_at: '2026-05-12T10:36:47+00:00'
                      updated_at: '2026-05-12T11:02:13+00:00'
  /push-configuration:
    post:
      tags:
        - 'Push configuration'
      summary: 'Push the PBX configuration (pbx)'
      operationId: postPushConfiguration
      description: |
        Push the authenticated PBX's configuration so that pending changes take
        effect. This is the programmatic equivalent of the "Push configuration"
        button in Cockpit, typically called after a number's call flow has been
        changed.

        The target PBX is derived from the API key; there is no request body.

        The presented PBX API key must carry the `push_configuration`
        ability/scope.

        **Rate limit:** 1 request per minute per PBX. Exceeding the limit returns
        `429` with a `Retry-After` header.
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        200:
          description: 'Configuration push recorded.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: pushed
                  pushed_at:
                    type: string
                    description: 'When the push was recorded, in the PBX timezone.'
                    example: '2026-06-15 09:12:04'
              example:
                status: pushed
                pushed_at: '2026-06-15 09:12:04'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The presented PBX API key does not carry the required
            `push_configuration` ability/scope.
        409:
          description: 'Configuration pushes are currently locked for this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: push_configuration_locked
                  message:
                    type: string
                    example: 'Configuration pushes are currently locked for this PBX.'
              example:
                error: push_configuration_locked
                message: 'Configuration pushes are currently locked for this PBX.'
        429:
          description: |
            Rate limit exceeded (max 1 push per minute per PBX). Wait `Retry-After`
            seconds before retrying.
          headers:
            Retry-After:
              description: 'Seconds to wait before the next allowed request.'
              schema:
                type: integer
                example: 46
            X-RateLimit-Limit:
              description: 'Maximum requests allowed in the window (1).'
              schema:
                type: integer
                example: 1
            X-RateLimit-Remaining:
              description: 'Requests remaining in the window (0 while throttled).'
              schema:
                type: integer
                example: 0
            X-RateLimit-Reset:
              description: 'Unix timestamp when the window resets.'
              schema:
                type: integer
                example: 1781265182
        500:
          description: 'The push could not be recorded; retry later.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: push_failed
                  message:
                    type: string
                    example: 'Could not push the configuration. Please try again later.'
              example:
                error: push_failed
                message: 'Could not push the configuration. Please try again later.'
  '/odoo/public/{partner}/catalogue':
    get:
      tags:
        - OdooCatalogue
      summary: "Read a distributor's Odoo product and subscription catalogue (user)"
      operationId: getOdooPartnerCatalogue
      description: |
        THE server-to-server endpoint of this surface. A distributor calls it from their own
        system to read their Odoo products and, if their token allows, their subscriptions.
        Every other Odoo endpoint is private to the cockpit partner interface.

        ## Auth

        "Public" here means "not the cockpit UI session". It is NOT unauthenticated. Send a
        Partner-owned Sanctum bearer token carrying the `odoo-catalogue` ability.

        THE PARTNER IN THE PATH IS FOR READABILITY ONLY. The token decides which Odoo is
        read, and the request 404s unless the token's partner matches the path. A partner id
        is an identifier, not a secret, so a mismatch cannot be allowed to succeed. It answers
        404 rather than 403 on purpose: confirming that some other partner id exists is itself
        a disclosure.

        Unlike the session endpoints, this route is NOT behind the partner interface kill
        switch, so it never answers 503.

        ## Two abilities, not one

        `odoo-catalogue` gets you products. Subscriptions need `odoo-subscriptions` ON TOP,
        because that block carries customer names and `recurring_monthly` /
        `recurring_total` / `non_recurring_total` for every sale order including drafts and
        churned deals. That is a commercial ledger rather than a price list, so it has to be
        asked for separately.

        ## Reading the subscription block

        The three subscription keys are ALWAYS present, and `subscriptions: []` alone never
        tells you why. Read `subscriptions_available` first, then
        `subscriptions_unavailable_reason`, which distinguishes three different situations a
        caller must act on differently: the token lacks the ability, the partner's Odoo lacks
        the Enterprise `sale_subscription` app, or the read failed. Products are still
        returned in all three cases, deliberately, rather than losing what the caller came
        for.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: partner
          in: path
          required: true
          description: "The cockpit Partner UUID. Must match the token's own partner or the answer is 404."
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: limit
          in: query
          description: 'Caps BOTH blocks. Out-of-range values are refused rather than clamped, unlike an earlier revision of this endpoint.'
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 100
          example: 100
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Catalogue retrieved'
                  data:
                    type: object
                    required:
                      - products
                      - subscriptions
                      - subscriptions_available
                      - subscriptions_unavailable_reason
                    properties:
                      products:
                        type: array
                        items:
                          type: object
                          description: 'A product as the PUBLIC catalogue exposes it. Deliberately narrower and flatter than the internal product model: `category` and `unit` are flattened to their labels, because an Odoo primary key is not useful to a third party and pins them to one instance.'
                          properties:
                            id:
                              type: integer
                              example: 812
                            name:
                              type:
                                - string
                                - 'null'
                              example: 'Desk Lamp'
                            reference:
                              type:
                                - string
                                - 'null'
                              description: "The internal model calls this `code` (Odoo's `default_code`)."
                              example: LAMP-001
                            price:
                              type: number
                              format: float
                              description: 'Sales price. Always a number, 0 when Odoo has none.'
                              example: 89.5
                            currency:
                              type:
                                - string
                                - 'null'
                              description: 'Currency NAME.'
                              example: EUR
                            category:
                              type:
                                - string
                                - 'null'
                              description: 'Category NAME only, already the full path. Not an object here.'
                              example: 'All / Office Furniture'
                            unit:
                              type:
                                - string
                                - 'null'
                              description: 'Unit of measure NAME only. Not an object here.'
                              example: Units
                            active:
                              type: boolean
                              example: true
                      subscriptions:
                        type: array
                        description: 'EMPTY does not mean "none". Check `subscriptions_available` before concluding anything from an empty array.'
                        items:
                          type: object
                          description: |-
                            A subscription as the PUBLIC catalogue exposes it. Narrower than the internal subscription model: the order's own tax totals and `customer_reference` are not disclosed.

                            Note the shape is not uniformly flattened. `plan` is reduced to its name, but `customer` stays an object, unlike every other label on this model.
                          properties:
                            id:
                              type: integer
                              example: 7731
                            name:
                              type:
                                - string
                                - 'null'
                              example: S00042
                            customer:
                              type:
                                - object
                                - 'null'
                              description: 'Still an object here, unlike `plan`.'
                              properties:
                                id:
                                  type: integer
                                  example: 315
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Northwind Trading'
                            plan:
                              type:
                                - string
                                - 'null'
                              description: 'Plan NAME only.'
                              example: Monthly
                            status:
                              type:
                                - string
                                - 'null'
                              description: "Odoo's own raw `subscription_state`, as on the internal model."
                              enum:
                                - 1_draft
                                - 2_renewal
                                - 3_progress
                                - 4_paused
                                - 5_renewed
                                - 6_churn
                                - 7_upsell
                                - 'null'
                              example: 3_progress
                            recurring_monthly:
                              type: number
                              format: float
                              example: 49.9
                            recurring_total:
                              type: number
                              format: float
                              example: 49.9
                            non_recurring_total:
                              type: number
                              format: float
                              example: 0
                            next_invoice_date:
                              type:
                                - string
                                - 'null'
                              format: date
                              example: '2026-09-01'
                            currency:
                              type:
                                - string
                                - 'null'
                              example: EUR
                            order_date:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2026-03-01 08:00:00'
                      subscriptions_available:
                        type: boolean
                        description: 'False when the block was withheld or could not be read, for any of the three reasons named below.'
                        example: true
                      subscriptions_unavailable_reason:
                        type:
                          - string
                          - 'null'
                        description: 'Null when `subscriptions_available` is true. Otherwise one of three distinct causes, which need different fixes: the token has no `odoo-subscriptions` ability (ask for a token that does), the instance lacks the Enterprise subscription app (a licensing matter), or the read failed (retry).'
                        example: null
              examples:
                withSubscriptions:
                  summary: 'Token carries both abilities'
                  value:
                    message: 'Catalogue retrieved'
                    data:
                      products:
                        -
                          id: 812
                          name: 'Desk Lamp'
                          reference: LAMP-001
                          price: 89.5
                          currency: EUR
                          category: 'All / Office Furniture'
                          unit: Units
                          active: true
                      subscriptions:
                        -
                          id: 7731
                          name: S00042
                          customer:
                            id: 315
                            name: 'Northwind Trading'
                          plan: Monthly
                          status: 3_progress
                          recurring_monthly: 49.9
                          recurring_total: 49.9
                          non_recurring_total: 0
                          next_invoice_date: '2026-09-01'
                          currency: EUR
                          order_date: '2026-03-01 08:00:00'
                      subscriptions_available: true
                      subscriptions_unavailable_reason: null
                abilityWithheld:
                  summary: 'Token may read products but not subscriptions'
                  value:
                    message: 'Catalogue retrieved'
                    data:
                      products:
                        -
                          id: 812
                          name: 'Desk Lamp'
                          reference: LAMP-001
                          price: 89.5
                          currency: EUR
                          category: 'All / Office Furniture'
                          unit: Units
                          active: true
                      subscriptions: {}
                      subscriptions_available: false
                      subscriptions_unavailable_reason: 'This token does not carry the odoo-subscriptions ability, so subscriptions were not read.'
        401:
          description: 'No valid bearer token.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: "The token is valid but not usable here: it is not owned by a Partner, it lacks the `odoo-catalogue` ability, or the partner's own status is not Active."
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'The partner account is not active.'
        404:
          description: 'The path names a different partner than the token belongs to, or names none at all. Deliberately 404 and not 403: a wrong id must be indistinguishable from a nonexistent one from outside.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Not Found.'
        422:
          description: |-
            TWO DIFFERENT BODIES share this status, and a client must handle both.
            Request validation failures carry `errors` and no `message`. Everything else (integration not configured, Odoo Sign app absent, an operation Odoo refused, a filter too broad for one Odoo domain to express, an Idempotency-Key reused for a different request) carries `message` and no `errors`.
            A too-broad filter is 422 rather than 502 because the request is answerable, just not as asked: narrowing it (a date range, a single `partner_id`) is something only the caller can decide, and retrying it unchanged cannot help.
          content:
            application/json:
              schema:
                oneOf:
                  -
                    type: object
                    title: 'Validation failure'
                    required:
                      - errors
                    properties:
                      errors:
                        type: object
                        additionalProperties:
                          type: array
                          items:
                            type: string
                  -
                    type: object
                    title: 'Rejected request'
                    required:
                      - message
                    properties:
                      message:
                        type: string
              examples:
                validation:
                  summary: 'A parameter failed validation'
                  value:
                    errors:
                      limit:
                        - 'The limit field must not be greater than 200.'
                noIntegration:
                  summary: 'The partner has no usable Odoo integration'
                  value:
                    message: 'The partner has no active Odoo integration.'
                signMissing:
                  summary: 'The Odoo Sign app is not installed'
                  value:
                    message: "The Odoo integration's Sign module is not installed."
                idempotencyReused:
                  summary: 'The key was already used for a different body'
                  value:
                    message: 'This Idempotency-Key was already used for a different request body.'
        429:
          description: "Rate limited: 30 requests per minute, keyed by ACCESS TOKEN rather than by partner, so each token issued to a distributor gets its own budget. One call returns a whole product and subscription list, which is why the cap is well below a page-at-a-time API's."
          headers:
            Retry-After:
              description: 'Seconds until the bucket refills.'
              schema:
                type: integer
              example: 22
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        502:
          description: |-
            The partner's Odoo could not be reached, or answered with a fault this endpoint does not translate into a more specific status. Usually retryable. The underlying Odoo fault is logged, not returned.
            ALSO here, and NOT retryable: an Odoo company scope that could not be resolved for the configured user. Every aggregate on this surface is filtered by the company ids that read produces, so it refuses rather than answering with figures drawn from companies the caller may not be allowed to see. The stored integration needs fixing.
            A filter too broad to express is NOT here: that is a 422, because narrowing it is the caller's decision.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Could not retrieve invoices from Odoo.'
  /odoo-installer/register-install:
    post:
      tags:
        - OdooInstaller
      summary: 'Register an Odoo installation (pbx)'
      operationId: postOdooInstallerRegisterInstall
      description: |
        Registers (upserts) the Odoo integration for the authenticated PBX and queues the
        installation job. Consumed by the Voxbi Installer module running inside a customer's
        Odoo. The PBX is resolved from the API key, so it is never part of the request body.
        Requires an API key carrying the `odoo-installer` ability.
      security:
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - odoo_url
                - odoo_db
                - odoo_version
                - service_user
                - service_key
                - service_uid
              properties:
                odoo_url:
                  type: string
                  maxLength: 255
                  description: "Base URL of the customer's Odoo instance."
                  example: 'https://erp.example.com'
                odoo_db:
                  type: string
                  maxLength: 128
                  example: example_prod
                odoo_version:
                  type: string
                  maxLength: 16
                  example: '17.0'
                service_user:
                  type: string
                  maxLength: 128
                  description: 'Login of the Odoo service account.'
                  example: svc_voxbi
                service_key:
                  type: string
                  maxLength: 255
                  writeOnly: true
                  description: 'Odoo service account API key. Stored encrypted and never returned.'
                  example: s3cr3t-service-key
                service_uid:
                  type: integer
                  description: 'Numeric Odoo user id of the service account.'
                  example: 7
                sync_sip_configurations:
                  type: boolean
                  default: false
                  description: 'When true, SIP configurations are pushed to Odoo VoIP.'
                  example: true
                is_active:
                  type: boolean
                  default: true
                  example: true
                installer_module_version:
                  type: string
                  maxLength: 32
                  example: 1.2.0
            example:
              odoo_url: 'https://erp.example.com'
              odoo_db: example_prod
              odoo_version: '17.0'
              service_user: svc_voxbi
              service_key: s3cr3t-service-key
              service_uid: 7
              sync_sip_configurations: true
              is_active: true
              installer_module_version: 1.2.0
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: 'Created. The integration is registered and the install job is queued.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  integration_id:
                    type: string
                    format: uuid
                  status_url:
                    type: string
                    format: uri
                    description: 'Poll this URL for the install status.'
              example:
                integration_id: 550e8400-e29b-41d4-a716-446655440000
                status_url: 'https://cockpit.voxbi.com/api/v1/odoo-installer/install-status'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /odoo-installer/install-status:
    get:
      tags:
        - OdooInstaller
      summary: 'Get the Odoo installation status (pbx)'
      operationId: getOdooInstallerInstallStatus
      description: |
        Returns the current install job status for the authenticated PBX's Odoo integration.
        Requires an API key carrying the `odoo-installer` ability.
      security:
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - pending
                      - processing
                      - success
                      - failed
                    description: 'Current install job status.'
                  results:
                    type: array
                    description: 'Per-step results of the install job. Empty until the job runs.'
                    items:
                      type: object
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
              example:
                status: pending
                results: {}
                updated_at: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'No Odoo integration exists for the authenticated PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: not_found
  /odoo-installer/get-integration:
    get:
      tags:
        - OdooInstaller
      summary: 'Get the Odoo integration (pbx)'
      operationId: getOdooInstallerGetIntegration
      description: |
        Returns the Odoo integration record for the authenticated PBX. The service account
        API key is never returned. Requires an API key carrying the `odoo-installer` ability.
      security:
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  integration_id:
                    type: string
                    format: uuid
                  pbx_id:
                    type: string
                    format: uuid
                  type:
                    type: string
                    example: odoo
                  is_active:
                    type: boolean
                  job_status:
                    type: string
                    enum:
                      - pending
                      - processing
                      - success
                      - failed
                  odoo_url:
                    type:
                      - string
                      - 'null'
                  odoo_db:
                    type:
                      - string
                      - 'null'
                  service_user:
                    type:
                      - string
                      - 'null'
                  odoo_version:
                    type:
                      - string
                      - 'null'
                  sync_sip_configurations:
                    type: boolean
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
              example:
                integration_id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                type: odoo
                is_active: true
                job_status: success
                odoo_url: 'https://erp.example.com'
                odoo_db: example_prod
                service_user: svc_voxbi
                odoo_version: '17.0'
                sync_sip_configurations: true
                updated_at: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'No Odoo integration exists for the authenticated PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: not_found
  /odoo-installer/update-and-fix-integration:
    post:
      tags:
        - OdooInstaller
      summary: 'Update and re-run the Odoo integration (pbx)'
      operationId: postOdooInstallerUpdateAndFixIntegration
      description: |
        Patches the supplied fields on the authenticated PBX's Odoo integration and re-queues
        the install job (job status is reset to `pending` and previous results are cleared).
        Every field is optional; only the fields you send are changed. The PBX is resolved
        from the API key. Requires an API key carrying the `odoo-installer` ability.
      security:
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                odoo_url:
                  type: string
                  maxLength: 255
                  example: 'https://erp.example.com'
                odoo_db:
                  type: string
                  maxLength: 128
                  example: example_prod
                odoo_version:
                  type: string
                  maxLength: 16
                  example: '17.0'
                service_user:
                  type: string
                  maxLength: 128
                  example: svc_voxbi
                service_key:
                  type: string
                  maxLength: 255
                  writeOnly: true
                  description: 'Odoo service account API key. Stored encrypted and never returned.'
                  example: s3cr3t-service-key
                service_uid:
                  type: integer
                  example: 7
                sync_sip_configurations:
                  type: boolean
                  example: true
                is_active:
                  type: boolean
                  example: true
                installer_module_version:
                  type: string
                  maxLength: 32
                  example: 1.2.0
            example:
              odoo_version: '17.0'
              is_active: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. The integration was updated and the install job re-queued.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  integration_id:
                    type: string
                    format: uuid
                  job_status:
                    type: string
                    enum:
                      - pending
                    description: 'Always reset to `pending` on save.'
                  status_url:
                    type: string
                    format: uri
              example:
                integration_id: 550e8400-e29b-41d4-a716-446655440000
                job_status: pending
                status_url: 'https://cockpit.voxbi.com/api/v1/odoo-installer/install-status'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'No Odoo integration exists for the authenticated PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: not_found
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /phone-numbers:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - PhoneNumbers
      summary: 'List Phone number'
      operationId: listPhoneNumbers
      description: |
        Returns a paginated list of phone numbers. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `number`, `is_active`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        External DID owned by the PBX. The optional `handling_strategy` JSON column
                        carries the inbound routing for the number (the previous top-level
                        `prefix_to_add`/`prefix_to_remove`/`routing` fields live inside it now).
                      required:
                        - id
                        - pbx_id
                        - number
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Phone number identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_carrier_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Default outbound SIP carrier for calls placed via this number'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        fallback_carrier_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Fallback SIP carrier used when the default carrier is unreachable'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        name:
                          type:
                            - string
                            - 'null'
                          maxLength: 64
                          description: 'Human-readable label for the number'
                          example: 'Support line'
                        language:
                          type:
                            - string
                            - 'null'
                          description: |
                            Announcement language for calls to this number (channel language). `null`
                            inherits the system default; ISO-639-1 code otherwise.
                          enum:
                            - en
                            - de
                            - fr
                            - lb
                            - es
                            - it
                            - pt
                            - nl
                            - pl
                            - ru
                            - tr
                            - sv
                            - da
                            - 'no'
                            - fi
                            - cs
                            - sk
                            - el
                            - hu
                            - ro
                            - bg
                            - hr
                            - uk
                            - ar
                            - he
                            - hi
                            - ja
                            - ko
                            - zh
                            - id
                            - ms
                            - th
                            - vi
                            - null
                          example: fr
                        number:
                          type: string
                          maxLength: 15
                          description: 'Phone number in E.164 (without leading +) or local format'
                          example: '12125550100'
                        international_prefix:
                          type:
                            - string
                            - 'null'
                          maxLength: 15
                          description: 'International dialling prefix associated with the number'
                          example: '1'
                        is_root:
                          type: boolean
                          description: 'Whether this DID is a root number (parent of suffixed CIDs)'
                          example: true
                        is_active:
                          type: boolean
                          description: 'Whether the number is provisioned and routable'
                          example: true
                        sync_source:
                          type: string
                          description: 'Provisioning origin of this number'
                          enum:
                            - manual
                            - provision
                          example: manual
                        handling_strategy:
                          type:
                            - object
                            - 'null'
                          description: |
                            Optional inbound routing configuration. `type` discriminates the shape
                            of `config`.
                          properties:
                            type:
                              type: string
                              enum:
                                - default
                                - rewrite
                                - call_flow
                                - extension
                                - user
                                - sip_device
                              example: call_flow
                            default_callflow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            no_ext_match_callflow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            prefix_to_remove:
                              type:
                                - string
                                - 'null'
                            prefix_to_add:
                              type:
                                - string
                                - 'null'
                            call_flow_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            extension_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            user_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            sip_device_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                        number_and_name:
                          type: string
                          description: 'Convenience label combining the number and its name'
                          example: '12125550100 (Support line)'
                          readOnly: true
                        number_without_international_prefix:
                          type: string
                          description: 'The number with its international prefix stripped'
                          example: '2125550100'
                          readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/phone-numbers/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - PhoneNumbers
      summary: 'Find Phone number by ID'
      operationId: getPhoneNumber
      description: |
        Returns the phone number identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  External DID owned by the PBX. The optional `handling_strategy` JSON column
                  carries the inbound routing for the number (the previous top-level
                  `prefix_to_add`/`prefix_to_remove`/`routing` fields live inside it now).
                required:
                  - id
                  - pbx_id
                  - number
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Phone number identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  default_carrier_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Default outbound SIP carrier for calls placed via this number'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  fallback_carrier_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Fallback SIP carrier used when the default carrier is unreachable'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  name:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: 'Human-readable label for the number'
                    example: 'Support line'
                  language:
                    type:
                      - string
                      - 'null'
                    description: |
                      Announcement language for calls to this number (channel language). `null`
                      inherits the system default; ISO-639-1 code otherwise.
                    enum:
                      - en
                      - de
                      - fr
                      - lb
                      - es
                      - it
                      - pt
                      - nl
                      - pl
                      - ru
                      - tr
                      - sv
                      - da
                      - 'no'
                      - fi
                      - cs
                      - sk
                      - el
                      - hu
                      - ro
                      - bg
                      - hr
                      - uk
                      - ar
                      - he
                      - hi
                      - ja
                      - ko
                      - zh
                      - id
                      - ms
                      - th
                      - vi
                      - null
                    example: fr
                  number:
                    type: string
                    maxLength: 15
                    description: 'Phone number in E.164 (without leading +) or local format'
                    example: '12125550100'
                  international_prefix:
                    type:
                      - string
                      - 'null'
                    maxLength: 15
                    description: 'International dialling prefix associated with the number'
                    example: '1'
                  is_root:
                    type: boolean
                    description: 'Whether this DID is a root number (parent of suffixed CIDs)'
                    example: true
                  is_active:
                    type: boolean
                    description: 'Whether the number is provisioned and routable'
                    example: true
                  sync_source:
                    type: string
                    description: 'Provisioning origin of this number'
                    enum:
                      - manual
                      - provision
                    example: manual
                  handling_strategy:
                    type:
                      - object
                      - 'null'
                    description: |
                      Optional inbound routing configuration. `type` discriminates the shape
                      of `config`.
                    properties:
                      type:
                        type: string
                        enum:
                          - default
                          - rewrite
                          - call_flow
                          - extension
                          - user
                          - sip_device
                        example: call_flow
                      default_callflow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      no_ext_match_callflow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      prefix_to_remove:
                        type:
                          - string
                          - 'null'
                      prefix_to_add:
                        type:
                          - string
                          - 'null'
                      call_flow_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      extension_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      user_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      sip_device_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                  number_and_name:
                    type: string
                    description: 'Convenience label combining the number and its name'
                    example: '12125550100 (Support line)'
                    readOnly: true
                  number_without_international_prefix:
                    type: string
                    description: 'The number with its international prefix stripped'
                    example: '2125550100'
                    readOnly: true
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /register-device:
    post:
      tags:
        - Users
      summary: 'Register a device for push notifications'
      operationId: postPushNotificationRegister
      description: |
        Creates a new push notification register. Validation rules and required fields are defined
        in the request body schema below.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
                - platform
              properties:
                token:
                  type: string
                  description: 'Device push notification token'
                  example: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
                platform:
                  type: string
                  description: 'Device platform (ios, android, web)'
                  example: ios
            example:
              token: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
              platform: ios
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: success
                message: 'Device registered for push notifications.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /unregister-device:
    post:
      tags:
        - Users
      summary: 'Unregister a device from push notifications'
      operationId: postPushNotificationUnregister
      description: |
        Creates a new push notification unregister. Validation rules and required fields are defined
        in the request body schema below.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
              properties:
                token:
                  type: string
                  description: 'Device push notification token to unregister'
                  example: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
            example:
              token: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: success
                message: 'Device unregistered.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /cleanup-old-tokens:
    post:
      tags:
        - Users
      summary: 'Clean up old push notification tokens'
      operationId: postPushNotificationCleanup
      description: |
        Triggers the action on the targeted push notification cleanup.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
                  removed:
                    type: integer
                    description: 'Number of tokens removed'
              example:
                status: success
                message: 'Old tokens cleaned up.'
                removed: 5
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /notify-device:
    post:
      tags:
        - Users
      summary: 'Send a push notification to a device'
      operationId: postPushNotificationNotifyDevice
      security:
        -
          PbxServerAuth: {}
      description: |
        Creates a new push notification notify device. Validation rules and required fields are
        defined in the request body schema below.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
                  description: 'Device push notification token'
                  example: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
                title:
                  type: string
                  description: 'Notification title'
                  example: 'Incoming Call'
                body:
                  type: string
                  description: 'Notification body'
                  example: 'John Doe is calling you'
                data:
                  type: object
                  description: 'Additional notification payload data'
                  additionalProperties: true
            example:
              token: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]'
              title: 'Incoming Call'
              body: 'John Doe is calling you'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  message:
                    type: string
              example:
                status: success
                message: 'Notification sent.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /queues:
    get:
      tags:
        - Queues
      summary: 'List queue'
      operationId: listQueues
      description: |
        Returns a paginated list of queues. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, pbx_id, pool_id, name, ring_strategy, music_on_hold_id, ring_busy_members, ring_twinnings, ring_duration, interval, wrap_up_time, exit_key, ring_empty, weight, mapping_id, voip_queue_id and call_flow_id.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Call queue distributes inbound calls across a set of member agents according
                        to a ring strategy. Callers wait while music-on-hold plays, and a member is
                        connected once one becomes available.

                        This schema documents the fields returned by the V1 API (the `responseAttributes`
                        projection of the Queue model), not the full database row. Timing fields are:
                        `ring_duration` (how long each agent is rung), `interval` (gap between ring
                        attempts), and `wrap_up_time` (post-call cool-down before the agent is rung
                        again). Queue membership is exposed inline through `users`; groups and pools
                        are managed via separate endpoints and are not part of this projection.
                      required:
                        - id
                        - pbx_id
                        - name
                        - ring_strategy
                        - ring_busy_members
                        - ring_duration
                        - interval
                        - wrap_up_time
                        - ring_empty
                        - enable_caller_position
                        - caller_position_announce_frequency
                        - caller_position_language
                        - users
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Queue identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant) that owns this queue'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type: string
                          maxLength: 128
                          description: 'Human-readable name of the queue'
                          example: 'Customer Support'
                        ring_strategy:
                          type: string
                          description: |
                            Order in which queue members are rung when a call arrives. `ring_all`
                            rings every member at once; `round_robin` cycles through members in turn;
                            `least_recent` favours the member idle the longest; `fewest_calls` favours
                            the member who has taken the fewest calls; `random` picks at random.
                          enum:
                            - fewest_calls
                            - least_recent
                            - round_robin
                            - ring_all
                            - random
                          example: ring_all
                        ring_busy_members:
                          type: boolean
                          description: 'Whether members already on a call are still rung for new queue calls'
                          example: false
                        ring_duration:
                          type: integer
                          format: int32
                          minimum: -1
                          description: 'Seconds to ring a member before moving on to the next; -1 means unlimited'
                          example: 20
                        interval:
                          type: integer
                          format: int32
                          minimum: 0
                          description: 'Seconds to wait between successive ring attempts (0 means no wait)'
                          example: 5
                        wrap_up_time:
                          type: integer
                          format: int32
                          minimum: 0
                          description: 'Seconds an agent stays unavailable after finishing a queue call (0 means no wait)'
                          example: 30
                        exit_key:
                          type:
                            - string
                            - 'null'
                          description: |
                            DTMF key a waiting caller can press to leave the queue and follow the
                            attached call flow. Null when no exit key is configured.
                          enum:
                            - '0'
                            - '1'
                            - '2'
                            - '3'
                            - '4'
                            - '5'
                            - '6'
                            - '7'
                            - '8'
                            - '9'
                            - '*'
                            - '#'
                          example: '0'
                        ring_empty:
                          type: boolean
                          description: 'Whether callers may enter (and the queue keeps ringing) even when no members are available'
                          example: false
                        enable_caller_position:
                          type: boolean
                          description: 'Whether waiting callers hear periodic announcements of their position in the queue'
                          example: false
                        caller_position_announce_frequency:
                          type: integer
                          format: int32
                          minimum: 0
                          description: "How often, in seconds, a waiting caller's position and/or estimated hold time is announced"
                          example: 10
                        caller_position_language:
                          type: string
                          description: 'Language used for the caller position announcement'
                          enum:
                            - en
                            - de
                            - fr
                          example: en
                        music_on_hold:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Identifier of the sound file (of type `music`) played to callers while
                            they wait. Null when no music-on-hold is configured.
                          example: 550e8400-e29b-41d4-a716-446655440004
                        users:
                          type: array
                          description: |
                            Queue member users, ordered by the tenant's configured name preference.
                            Each item is a User resource. The array is empty when no users are
                            assigned to the queue.
                          items:
                            type: object
                            description: |
                              PBX user. Each user belongs to exactly one Pbx, owns optional extensions
                              and devices, and carries a large set of feature flags controlling what they
                              can do in the Voxbi UI and on the telephony stack.

                              Secrets and credentials are never exposed through the API. Relation keys are
                              opt-in via `?include=`.
                            required:
                              - id
                              - pbx_id
                              - first_name
                              - email
                              - status
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'User identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              first_name:
                                type: string
                                maxLength: 64
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 64
                                example: Smith
                              name:
                                type: string
                                readOnly: true
                                description: 'Combined display name (accessor, respects PBX formatting settings)'
                                example: 'Jane Smith'
                              full_name_with_email:
                                type: string
                                readOnly: true
                                description: 'Convenience label combining the display name and email'
                                example: 'Jane Smith <jane.smith@example.com>'
                              email:
                                type: string
                                format: email
                                maxLength: 100
                                example: jane.smith@example.com
                              status:
                                type: string
                                enum:
                                  - enabled
                                  - disabled
                                example: enabled
                              type:
                                type: string
                                description: 'User category'
                                enum:
                                  - user
                                  - pickup_line
                                example: user
                              language:
                                type: string
                                description: 'Preferred UI language'
                                enum:
                                  - en
                                  - de
                                  - fr
                                example: en
                              sync_source:
                                type: string
                                description: 'Provisioning origin'
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                  - microsoft_entra
                                example: manual
                              vip:
                                type: boolean
                                description: 'Whether the user is flagged as VIP'
                                example: false
                              show_in_address_book:
                                type: boolean
                                description: 'Whether the user appears in the shared address book'
                                example: true
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Default outbound CID for this user'
                                example: 550e8400-e29b-41d4-a716-446655440004
                              caller_identity_internal_extension_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension shown as the internal caller ID'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              caller_identity_external_extension_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension shown as the external caller ID'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              allow_telephony:
                                type: boolean
                                description: 'Whether the user can place and receive calls'
                                example: true
                              allow_call_forwarding:
                                type: boolean
                                example: true
                              allow_change_twinning_dest:
                                type: boolean
                                description: 'Whether the user may change their twinning destination'
                                example: true
                              allow_dnd:
                                type: boolean
                                description: 'Whether the user may set their own Do Not Disturb'
                                example: true
                              allow_status_changer:
                                type: boolean
                                description: "Whether the user may change other users' statuses"
                                example: false
                              allow_anonymous_calls:
                                type: boolean
                                description: 'Whether the user is allowed to place anonymous outbound calls'
                                example: false
                              allow_international_calls:
                                type: boolean
                                example: false
                              allow_eu_calls:
                                type: boolean
                                example: true
                              allow_national_calls:
                                type: boolean
                                example: true
                              allow_premium_numbers:
                                type: boolean
                                example: false
                              allow_sms:
                                type: boolean
                                example: false
                              allow_manage_global_contacts:
                                type: boolean
                                example: false
                              allow_manage_voicemail_parameters:
                                type: boolean
                                example: true
                              allow_in_call_recording:
                                type: boolean
                                description: 'Whether the user can start/stop recording during a call'
                                example: false
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: 'Whether the PBX default outbound numbers are usable by this user'
                                example: true
                              allow_grafana_access:
                                type: boolean
                                description: 'Whether the user can access the Grafana dashboards'
                                example: false
                              allow_right_to_disconnect:
                                type: boolean
                                description: 'Whether the user may set their own right-to-disconnect schedule'
                                example: true
                              right_to_disconnect:
                                type: boolean
                                description: 'Whether the right-to-disconnect rule is currently enforced'
                                example: false
                              concurrent_calls:
                                type: boolean
                                description: 'Whether the user may have multiple simultaneous calls'
                                example: true
                              extension_roaming:
                                type: boolean
                                description: 'Whether the user may hot-desk by logging into other devices'
                                example: true
                              record_your_calls:
                                type: boolean
                                description: 'Default per-call recording flag for outbound external calls'
                                example: false
                              record_your_internal_calls:
                                type: integer
                                description: |
                                  Tri-state flag controlling internal-call recording (0 = off, 1 = on,
                                  2 = follow PBX default). Stored as an integer despite the boolean-style
                                  name.
                                example: 2
                              access_all_call_recordings:
                                type: boolean
                                description: 'Whether the user may access call recordings of others'
                                example: false
                              call_recordings_visibility:
                                type: string
                                enum:
                                  - all_calls
                                  - own_calls_only
                                example: own_calls_only
                              call_information_visibility:
                                type: string
                                enum:
                                  - none
                                  - own_calls
                                  - own_group_only
                                example: own_calls
                              send_missed_call_via_email:
                                type: boolean
                                example: true
                              limit_email_missed_call_to_direct:
                                type: boolean
                                description: 'Whether missed-call emails are limited to directly-dialled calls'
                                example: false
                              show_caller_id_for_twinning_call:
                                type: integer
                                description: |
                                  Tri-state flag controlling caller-ID display on twinning calls (0 = off,
                                  1 = on, 2 = follow PBX default).
                                example: 2
                              voicemail_type:
                                type: string
                                description: 'Voicemail mode'
                                enum:
                                  - disabled
                                  - enabled
                                  - internal
                                  - external
                                example: internal
                              voicemail_destination:
                                type: string
                                description: 'Where voicemail notifications are sent'
                                enum:
                                  - email_only
                                  - email_and_phone
                                example: email_only
                              invited_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'When the user was invited (if onboarding via invitation)'
                                example: null
                              accepted_invitation_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'When the user accepted their invitation'
                                example: null
                              email_verified_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-02-15T10:00:00Z'
                                readOnly: true
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              extensions:
                                type: array
                                description: 'Extensions owned by the user. Returned only when requested via `?include=extensions`.'
                                items:
                                  type: object
                                  description: |
                                    Internal dial number assigned to a user, device, queue, or other PBX entity.
                                    Per-direction call recording is controlled by the two `record_*_calls` flags.
                                    The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                                    (always present); the full `assigned_to` object is opt-in.
                                  required:
                                    - id
                                    - pbx_id
                                    - number
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Extension identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    assigned_to_type:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Friendly type of the entity this extension is assigned to'
                                      enum:
                                        - user
                                        - sip_device
                                        - famulor_agent
                                      example: user
                                    assigned_to_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Identifier of the entity this extension is assigned to'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    external_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow applied to external inbound calls hitting this extension'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    internal_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow applied to internal calls hitting this extension'
                                      example: 550e8400-e29b-41d4-a716-446655440004
                                    number:
                                      type: string
                                      maxLength: 16
                                      description: 'Dialable extension digits'
                                      example: '1337'
                                    name:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Display name for the extension'
                                      example: 'Support line'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'Front-line support line'
                                    record_external_calls:
                                      type: boolean
                                      description: 'Whether external calls on this extension are recorded'
                                      example: true
                                    record_internal_calls:
                                      type: boolean
                                      description: 'Whether internal calls on this extension are recorded'
                                      example: false
                                    sync_source:
                                      type: string
                                      description: 'Provisioning origin (cast to ExtensionSyncSource)'
                                      enum:
                                        - manual
                                        - provision
                                        - legacy_import
                                      example: manual
                                    full_name_with_extension_number:
                                      type:
                                        - string
                                        - 'null'
                                      description: "Convenience label combining the assignee's name and the extension number"
                                      example: 'Jane Smith (1337)'
                                      readOnly: true
                                    assigned_to:
                                      type: object
                                      description: |
                                        The resolved owner of this extension; shape varies by `assigned_to_type`.
                                        Returned only when requested via `?include=user` (or `?include=sipDevice`
                                        / `?include=famulorAgent`).
                                    employee_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: |
                                        Identifier of the employee record linked to the assigned user.
                                        Returned only when requested via `?include=user.employee`.
                                      example: 550e8400-e29b-41d4-a716-446655440005
                                    department_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: |
                                        Department of the assigned user's employee, taken from their currently
                                        active contract (null when the employee has no active contract).
                                        Returned only when requested via `?include=user.employee`.
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                    is_favorite:
                                      type: boolean
                                      description: |
                                        Whether the extension's user is one of the **calling user's** favourites.
                                        PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                                        OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                                      example: false
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              groups:
                                type: array
                                description: 'Groups the user belongs to. Returned only when requested via `?include=groups`.'
                                items:
                                  type: object
                                  description: |
                                    Group of users that share routing defaults and (optionally) a common caller
                                    identity. Many fields are foreign keys pointing at defaults used when the
                                    group's users place or receive calls.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Group identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    default_internal_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for internal calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    default_external_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for external calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    extension_id_shown_outside_the_group:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Extension displayed to non-group members'
                                      example: 550e8400-e29b-41d4-a716-446655440005
                                    default_caller_identity_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: "Default caller identity applied to the group's outbound calls"
                                      example: 550e8400-e29b-41d4-a716-446655440004
                                    external_uid:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'External identifier from a CRM or directory sync'
                                      example: grp-support
                                    allow_call_pickups:
                                      type: boolean
                                      description: "Whether group members may pick up each others' ringing calls"
                                      example: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      example: 'Support team'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'First-line support'
                                    allow_default_pbxes_outgoing_phone_numbers:
                                      type: boolean
                                      description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                      example: false
                                    display_tab_to_everyone_inside_voxbi:
                                      type: boolean
                                      description: "Whether the group's tab is shown to everyone in the PBX"
                                      example: false
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    users:
                                      type: array
                                      description: |
                                        Members of the group, each as a user reference. Returned only when
                                        requested via `?include=users`.
                                      items:
                                        type: object
                                        properties:
                                          id:
                                            type: string
                                            format: uuid
                                            example: 550e8400-e29b-41d4-a716-446655440006
                                            readOnly: true
                                          first_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Jane
                                          last_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Smith
                                          email:
                                            type:
                                              - string
                                              - 'null'
                                            format: email
                                            example: jane.smith@example.com
                              allow_manage_group_contacts:
                                type: array
                                description: |
                                  Groups whose contacts the user may manage. Returned only when requested
                                  via `?include=allowManageGroupContacts`.
                                items:
                                  type: object
                                  description: |
                                    Group of users that share routing defaults and (optionally) a common caller
                                    identity. Many fields are foreign keys pointing at defaults used when the
                                    group's users place or receive calls.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Group identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    default_internal_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for internal calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    default_external_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for external calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    extension_id_shown_outside_the_group:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Extension displayed to non-group members'
                                      example: 550e8400-e29b-41d4-a716-446655440005
                                    default_caller_identity_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: "Default caller identity applied to the group's outbound calls"
                                      example: 550e8400-e29b-41d4-a716-446655440004
                                    external_uid:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'External identifier from a CRM or directory sync'
                                      example: grp-support
                                    allow_call_pickups:
                                      type: boolean
                                      description: "Whether group members may pick up each others' ringing calls"
                                      example: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      example: 'Support team'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'First-line support'
                                    allow_default_pbxes_outgoing_phone_numbers:
                                      type: boolean
                                      description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                      example: false
                                    display_tab_to_everyone_inside_voxbi:
                                      type: boolean
                                      description: "Whether the group's tab is shown to everyone in the PBX"
                                      example: false
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    users:
                                      type: array
                                      description: |
                                        Members of the group, each as a user reference. Returned only when
                                        requested via `?include=users`.
                                      items:
                                        type: object
                                        properties:
                                          id:
                                            type: string
                                            format: uuid
                                            example: 550e8400-e29b-41d4-a716-446655440006
                                            readOnly: true
                                          first_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Jane
                                          last_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Smith
                                          email:
                                            type:
                                              - string
                                              - 'null'
                                            format: email
                                            example: jane.smith@example.com
                              allow_access_to_group_contacts:
                                type: array
                                description: |
                                  Groups whose contacts the user may access. Returned only when requested
                                  via `?include=allowAccessToGroupContacts`.
                                items:
                                  type: object
                                  description: |
                                    Group of users that share routing defaults and (optionally) a common caller
                                    identity. Many fields are foreign keys pointing at defaults used when the
                                    group's users place or receive calls.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Group identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    default_internal_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for internal calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    default_external_call_flow_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Call flow used for external calls reaching this group'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    extension_id_shown_outside_the_group:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Extension displayed to non-group members'
                                      example: 550e8400-e29b-41d4-a716-446655440005
                                    default_caller_identity_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: "Default caller identity applied to the group's outbound calls"
                                      example: 550e8400-e29b-41d4-a716-446655440004
                                    external_uid:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'External identifier from a CRM or directory sync'
                                      example: grp-support
                                    allow_call_pickups:
                                      type: boolean
                                      description: "Whether group members may pick up each others' ringing calls"
                                      example: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      example: 'Support team'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'First-line support'
                                    allow_default_pbxes_outgoing_phone_numbers:
                                      type: boolean
                                      description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                      example: false
                                    display_tab_to_everyone_inside_voxbi:
                                      type: boolean
                                      description: "Whether the group's tab is shown to everyone in the PBX"
                                      example: false
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    users:
                                      type: array
                                      description: |
                                        Members of the group, each as a user reference. Returned only when
                                        requested via `?include=users`.
                                      items:
                                        type: object
                                        properties:
                                          id:
                                            type: string
                                            format: uuid
                                            example: 550e8400-e29b-41d4-a716-446655440006
                                            readOnly: true
                                          first_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Jane
                                          last_name:
                                            type:
                                              - string
                                              - 'null'
                                            example: Smith
                                          email:
                                            type:
                                              - string
                                              - 'null'
                                            format: email
                                            example: jane.smith@example.com
                              sip_devices:
                                type: array
                                description: 'SIP devices assigned to the user. Returned only when requested via `?include=sipDevices`.'
                                items:
                                  type: object
                                  description: |
                                    Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                                    against the PBX. The device owner is exposed as a friendly `target_type`
                                    (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                                    The SIP password is never exposed.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                    - is_enabled
                                    - type
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'SIP device identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    target_type:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Friendly type of the entity the device is assigned to'
                                      enum:
                                        - user
                                        - extension
                                      example: user
                                    target_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Identifier of the target entity'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    extension_id_shown_for_internal_calls:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: "Extension displayed in the device's caller ID for internal calls"
                                      example: null
                                    roaming_user_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'User currently roamed onto this device'
                                      example: null
                                    location_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Physical location the device is installed at'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    parent_sip_device_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                                      example: null
                                    name:
                                      type: string
                                      maxLength: 128
                                      example: 'Reception desk phone'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'Front-desk Yealink T46U'
                                    is_enabled:
                                      type: boolean
                                      description: 'Whether the device is currently enabled'
                                      example: true
                                    ip_internal:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Last-seen internal IP'
                                      example: 192.168.1.42
                                    ip_external:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Last-seen external IP'
                                      example: 203.0.113.10
                                    user_agent:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'SIP User-Agent string reported by the device'
                                      example: 'Yealink SIP-T46U 108.86.0.10'
                                    mac:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'MAC address'
                                      example: '00:0a:95:9d:68:16'
                                    vlan_phone:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'VLAN id for the phone interface'
                                      example: 100
                                    vlan_pc:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'VLAN id for the PC pass-through interface'
                                      example: 200
                                    sip_username:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 24
                                      description: 'SIP authentication username'
                                      example: device_001
                                    alt_username:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Alternate SIP username (used for multi-line registrations)'
                                      example: null
                                    transport:
                                      type: string
                                      description: 'SIP transport'
                                      enum:
                                        - udp
                                        - tcp
                                        - tls
                                      example: tls
                                    type:
                                      type: string
                                      description: 'Device provisioning category'
                                      enum:
                                        - auto
                                        - manual
                                        - gigaset
                                        - trunk
                                      example: auto
                                    allow_roaming:
                                      type: boolean
                                      description: 'Whether the device accepts roamed-in users'
                                      example: false
                                    language:
                                      type: string
                                      description: 'Display language for the device'
                                      example: en
                                    easy_deploy:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp until which the device is in easy-deploy mode'
                                      example: null
                                    notify:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp at which a SIP NOTIFY was last requested'
                                      example: null
                                    allow_default_pbxes_outgoing_phone_numbers:
                                      type: boolean
                                      description: 'Whether the PBX default outbound numbers are usable from this device'
                                      example: false
                                    sync_source:
                                      type: string
                                      description: 'Provisioning origin'
                                      enum:
                                        - manual
                                        - provision
                                        - legacy_import
                                      example: provision
                                    custom_provisioning:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Custom provisioning template snippet'
                                      example: null
                                    last_seen:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Last time the device registered'
                                      example: '2024-03-01T08:29:07Z'
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    target:
                                      type: object
                                      description: |
                                        The resolved device owner (a user or an extension); shape varies by
                                        `target_type`. Returned only when requested via `?include=target`.
                                    tags:
                                      type: array
                                      description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                                      items:
                                        type: object
                                        description: |
                                          Free-form label that can be attached to users, SIP devices, phone numbers, and
                                          other tenant resources for grouping, filtering, and reporting. Tags are scoped
                                          to a single Pbx (tenant). Associations to the resources a tag is applied to are
                                          held on the relevant pivot tables, not on this schema.
                                        required:
                                          - id
                                          - pbx_id
                                          - name
                                        properties:
                                          id:
                                            type: string
                                            format: uuid
                                            description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                            example: 550e8400-e29b-41d4-a716-446655440000
                                            readOnly: true
                                          pbx_id:
                                            type: string
                                            format: uuid
                                            description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                            example: 550e8400-e29b-41d4-a716-446655440001
                                            readOnly: true
                                          name:
                                            type: string
                                            maxLength: 64
                                            description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                            example: 'VIP Customers'
                                          description:
                                            type:
                                              - string
                                              - 'null'
                                            maxLength: 255
                                            description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                            example: 'Customers with priority routing and dedicated agents.'
                                          created_at:
                                            type:
                                              - string
                                              - 'null'
                                            format: date-time
                                            description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                            example: '2024-03-01T08:29:07Z'
                                            readOnly: true
                                          updated_at:
                                            type:
                                              - string
                                              - 'null'
                                            format: date-time
                                            description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                            example: '2024-03-01T08:29:07Z'
                                            readOnly: true
                                    caller_identities:
                                      type: array
                                      description: |
                                        Caller identities available to this device. Returned only when requested
                                        via `?include=callerIdentities`.
                                      items:
                                        type: object
                                    location:
                                      description: |
                                        The resolved installation location. Returned only when requested via
                                        `?include=location`.
                                      allOf:
                                        -
                                          type: object
                                          description: |
                                            Physical office or site associated with a PBX. Locations form a nested-set
                                            tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                            used for emergency call routing.
                                          required:
                                            - id
                                            - pbx_id
                                            - name
                                          properties:
                                            id:
                                              type: string
                                              format: uuid
                                              description: 'Location identifier'
                                              example: 550e8400-e29b-41d4-a716-446655440000
                                              readOnly: true
                                            pbx_id:
                                              type: string
                                              format: uuid
                                              description: 'Pbx identifier (tenant)'
                                              example: 550e8400-e29b-41d4-a716-446655440001
                                            company_id:
                                              type:
                                                - string
                                                - 'null'
                                              format: uuid
                                              description: 'Owning company identifier'
                                              example: 550e8400-e29b-41d4-a716-446655440004
                                            parent_id:
                                              type:
                                                - string
                                                - 'null'
                                              format: uuid
                                              description: 'Parent location identifier in the nested-set tree'
                                              example: 550e8400-e29b-41d4-a716-446655440002
                                            name:
                                              type: string
                                              maxLength: 64
                                              example: 'Luxembourg HQ'
                                            description:
                                              type:
                                                - string
                                                - 'null'
                                              maxLength: 255
                                              example: 'Main office, 5th floor'
                                            street_no:
                                              type:
                                                - string
                                                - 'null'
                                              description: 'Street number portion of the address'
                                              example: '12'
                                            street:
                                              type:
                                                - string
                                                - 'null'
                                              example: 'Main Street'
                                            city:
                                              type:
                                                - string
                                                - 'null'
                                              example: Luxembourg
                                            postal:
                                              type:
                                                - string
                                                - 'null'
                                              description: 'Postal code'
                                              example: '1234'
                                            country_id:
                                              type:
                                                - string
                                                - 'null'
                                              format: uuid
                                              description: 'Country identifier'
                                              example: 550e8400-e29b-41d4-a716-446655440003
                                            lft:
                                              type:
                                                - integer
                                                - 'null'
                                              description: 'Nested-set left bound'
                                              example: 1
                                            rgt:
                                              type:
                                                - integer
                                                - 'null'
                                              description: 'Nested-set right bound'
                                              example: 10
                                            depth:
                                              type:
                                                - integer
                                                - 'null'
                                              description: 'Tree depth (0 for root locations)'
                                              example: 0
                                            enable_location_as_presence_status:
                                              type: boolean
                                              description: 'Whether this location can be used as a presence status value'
                                              example: false
                                            style:
                                              type:
                                                - object
                                                - 'null'
                                              description: 'Optional presentation style (badge icon and colours) for the location'
                                              example:
                                                icon_class: la-map-pin
                                                bg_color: '#3490dc'
                                                font_color: '#ffffff'
                                            is_fixed_location:
                                              type: boolean
                                              description: 'Whether this is a fixed (geofenced) physical location'
                                              example: true
                                            latitude:
                                              type:
                                                - number
                                                - 'null'
                                              format: float
                                              description: 'Latitude of the location, in decimal degrees'
                                              example: 49.6116
                                            longitude:
                                              type:
                                                - number
                                                - 'null'
                                              format: float
                                              description: 'Longitude of the location, in decimal degrees'
                                              example: 6.1319
                                            geofence_radius_m:
                                              type:
                                                - integer
                                                - 'null'
                                              description: 'Geofence radius around the location, in metres'
                                              example: 100
                                            created_at:
                                              type:
                                                - string
                                                - 'null'
                                              format: date-time
                                              example: '2024-03-01T08:29:07Z'
                                              readOnly: true
                                            updated_at:
                                              type:
                                                - string
                                                - 'null'
                                              format: date-time
                                              example: '2024-03-01T08:29:07Z'
                                              readOnly: true
                              twinnings:
                                type: array
                                description: 'Twinnings configured for the user. Returned only when requested via `?include=twinnings`.'
                                items:
                                  type: object
                                  description: |
                                    Twinning: an external destination that rings alongside a user's extension
                                    (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                                    the twinned destination rings in parallel so the call can be answered away
                                    from the desk phone. Tenant scoping is derived from the attached user; this
                                    resource has no direct `pbx_id` column of its own.
                                  required:
                                    - id
                                    - user_id
                                    - status
                                    - phone_number
                                    - delay
                                    - sync_source
                                    - type
                                    - dial_strategy
                                    - fmc_enabled
                                    - backup_phone_number
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Unique identifier of the twinning.'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    user_id:
                                      type: string
                                      format: uuid
                                      description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    status:
                                      type: string
                                      enum:
                                        - enabled
                                        - disabled
                                      description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                                      example: enabled
                                    phone_number:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                                      example: '+12125550100'
                                    delay:
                                      type: integer
                                      format: int32
                                      minimum: 0
                                      description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                                      example: 5
                                    sync_source:
                                      type: string
                                      enum:
                                        - manual
                                        - provision
                                        - legacy_import
                                      description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                                      example: manual
                                    type:
                                      type: string
                                      enum:
                                        - mobile
                                        - teams
                                      description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                                      example: mobile
                                    dial_strategy:
                                      type: string
                                      enum:
                                        - gsm_only
                                        - voip_only
                                        - voip_and_gsm_fallback
                                      description: |
                                        How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                                        `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                                        VoIP first and falls back to GSM. Only meaningful for mobile-type
                                        twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                                      example: voip_and_gsm_fallback
                                    fmc_enabled:
                                      type: boolean
                                      description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                                      example: false
                                    backup_phone_number:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                                      example: '+12125550101'
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              caller_identities:
                                type: array
                                description: |
                                  Effective (inherited) caller identities for the user: own plus those of
                                  the user's groups plus the PBX's. Returned only when requested via
                                  `?include=callerIdentities`.
                                items:
                                  type: object
                              locations:
                                type: array
                                description: 'Locations the user is associated with. Returned only when requested via `?include=locations`.'
                                items:
                                  type: object
                                  description: |
                                    Physical office or site associated with a PBX. Locations form a nested-set
                                    tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                    used for emergency call routing.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Location identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Pbx identifier (tenant)'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                    company_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Owning company identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440004
                                    parent_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Parent location identifier in the nested-set tree'
                                      example: 550e8400-e29b-41d4-a716-446655440002
                                    name:
                                      type: string
                                      maxLength: 64
                                      example: 'Luxembourg HQ'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      example: 'Main office, 5th floor'
                                    street_no:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Street number portion of the address'
                                      example: '12'
                                    street:
                                      type:
                                        - string
                                        - 'null'
                                      example: 'Main Street'
                                    city:
                                      type:
                                        - string
                                        - 'null'
                                      example: Luxembourg
                                    postal:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Postal code'
                                      example: '1234'
                                    country_id:
                                      type:
                                        - string
                                        - 'null'
                                      format: uuid
                                      description: 'Country identifier'
                                      example: 550e8400-e29b-41d4-a716-446655440003
                                    lft:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'Nested-set left bound'
                                      example: 1
                                    rgt:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'Nested-set right bound'
                                      example: 10
                                    depth:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'Tree depth (0 for root locations)'
                                      example: 0
                                    enable_location_as_presence_status:
                                      type: boolean
                                      description: 'Whether this location can be used as a presence status value'
                                      example: false
                                    style:
                                      type:
                                        - object
                                        - 'null'
                                      description: 'Optional presentation style (badge icon and colours) for the location'
                                      example:
                                        icon_class: la-map-pin
                                        bg_color: '#3490dc'
                                        font_color: '#ffffff'
                                    is_fixed_location:
                                      type: boolean
                                      description: 'Whether this is a fixed (geofenced) physical location'
                                      example: true
                                    latitude:
                                      type:
                                        - number
                                        - 'null'
                                      format: float
                                      description: 'Latitude of the location, in decimal degrees'
                                      example: 49.6116
                                    longitude:
                                      type:
                                        - number
                                        - 'null'
                                      format: float
                                      description: 'Longitude of the location, in decimal degrees'
                                      example: 6.1319
                                    geofence_radius_m:
                                      type:
                                        - integer
                                        - 'null'
                                      description: 'Geofence radius around the location, in metres'
                                      example: 100
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              languages:
                                type: array
                                description: 'Languages the user is associated with. Returned only when requested via `?include=languages`.'
                                items:
                                  type: object
                                  description: |
                                    A language defined for the tenant, used to label sound files, voice prompts
                                    (IVR announcements), and per-user language preferences. Each language belongs
                                    to exactly one Pbx (tenant) and is identified by a free-text name.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Unique language identifier (UUID).'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Identifier of the Pbx (tenant) that owns this language.'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                      readOnly: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      description: 'Human-readable language name as shown in the cockpit and selectors.'
                                      example: English
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              tags:
                                type: array
                                description: 'Tags attached to the user. Returned only when requested via `?include=tags`.'
                                items:
                                  type: object
                                  description: |
                                    Free-form label that can be attached to users, SIP devices, phone numbers, and
                                    other tenant resources for grouping, filtering, and reporting. Tags are scoped
                                    to a single Pbx (tenant). Associations to the resources a tag is applied to are
                                    held on the relevant pivot tables, not on this schema.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                      readOnly: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                      example: 'VIP Customers'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                      example: 'Customers with priority routing and dedicated agents.'
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              queues:
                                type: array
                                description: 'Queues the user is a member of. Returned only when requested via `?include=queues`.'
                                items:
                                  type: object
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/queues/{id}':
    get:
      tags:
        - Queues
      summary: 'Get a Queue'
      operationId: getQueue
      description: |
        Returns the queue identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Call queue distributes inbound calls across a set of member agents according
                  to a ring strategy. Callers wait while music-on-hold plays, and a member is
                  connected once one becomes available.

                  This schema documents the fields returned by the V1 API (the `responseAttributes`
                  projection of the Queue model), not the full database row. Timing fields are:
                  `ring_duration` (how long each agent is rung), `interval` (gap between ring
                  attempts), and `wrap_up_time` (post-call cool-down before the agent is rung
                  again). Queue membership is exposed inline through `users`; groups and pools
                  are managed via separate endpoints and are not part of this projection.
                required:
                  - id
                  - pbx_id
                  - name
                  - ring_strategy
                  - ring_busy_members
                  - ring_duration
                  - interval
                  - wrap_up_time
                  - ring_empty
                  - enable_caller_position
                  - caller_position_announce_frequency
                  - caller_position_language
                  - users
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Queue identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant) that owns this queue'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 128
                    description: 'Human-readable name of the queue'
                    example: 'Customer Support'
                  ring_strategy:
                    type: string
                    description: |
                      Order in which queue members are rung when a call arrives. `ring_all`
                      rings every member at once; `round_robin` cycles through members in turn;
                      `least_recent` favours the member idle the longest; `fewest_calls` favours
                      the member who has taken the fewest calls; `random` picks at random.
                    enum:
                      - fewest_calls
                      - least_recent
                      - round_robin
                      - ring_all
                      - random
                    example: ring_all
                  ring_busy_members:
                    type: boolean
                    description: 'Whether members already on a call are still rung for new queue calls'
                    example: false
                  ring_duration:
                    type: integer
                    format: int32
                    minimum: -1
                    description: 'Seconds to ring a member before moving on to the next; -1 means unlimited'
                    example: 20
                  interval:
                    type: integer
                    format: int32
                    minimum: 0
                    description: 'Seconds to wait between successive ring attempts (0 means no wait)'
                    example: 5
                  wrap_up_time:
                    type: integer
                    format: int32
                    minimum: 0
                    description: 'Seconds an agent stays unavailable after finishing a queue call (0 means no wait)'
                    example: 30
                  exit_key:
                    type:
                      - string
                      - 'null'
                    description: |
                      DTMF key a waiting caller can press to leave the queue and follow the
                      attached call flow. Null when no exit key is configured.
                    enum:
                      - '0'
                      - '1'
                      - '2'
                      - '3'
                      - '4'
                      - '5'
                      - '6'
                      - '7'
                      - '8'
                      - '9'
                      - '*'
                      - '#'
                    example: '0'
                  ring_empty:
                    type: boolean
                    description: 'Whether callers may enter (and the queue keeps ringing) even when no members are available'
                    example: false
                  enable_caller_position:
                    type: boolean
                    description: 'Whether waiting callers hear periodic announcements of their position in the queue'
                    example: false
                  caller_position_announce_frequency:
                    type: integer
                    format: int32
                    minimum: 0
                    description: "How often, in seconds, a waiting caller's position and/or estimated hold time is announced"
                    example: 10
                  caller_position_language:
                    type: string
                    description: 'Language used for the caller position announcement'
                    enum:
                      - en
                      - de
                      - fr
                    example: en
                  music_on_hold:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: |
                      Identifier of the sound file (of type `music`) played to callers while
                      they wait. Null when no music-on-hold is configured.
                    example: 550e8400-e29b-41d4-a716-446655440004
                  users:
                    type: array
                    description: |
                      Queue member users, ordered by the tenant's configured name preference.
                      Each item is a User resource. The array is empty when no users are
                      assigned to the queue.
                    items:
                      type: object
                      description: |
                        PBX user. Each user belongs to exactly one Pbx, owns optional extensions
                        and devices, and carries a large set of feature flags controlling what they
                        can do in the Voxbi UI and on the telephony stack.

                        Secrets and credentials are never exposed through the API. Relation keys are
                        opt-in via `?include=`.
                      required:
                        - id
                        - pbx_id
                        - first_name
                        - email
                        - status
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'User identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        first_name:
                          type: string
                          maxLength: 64
                          example: Jane
                        last_name:
                          type:
                            - string
                            - 'null'
                          maxLength: 64
                          example: Smith
                        name:
                          type: string
                          readOnly: true
                          description: 'Combined display name (accessor, respects PBX formatting settings)'
                          example: 'Jane Smith'
                        full_name_with_email:
                          type: string
                          readOnly: true
                          description: 'Convenience label combining the display name and email'
                          example: 'Jane Smith <jane.smith@example.com>'
                        email:
                          type: string
                          format: email
                          maxLength: 100
                          example: jane.smith@example.com
                        status:
                          type: string
                          enum:
                            - enabled
                            - disabled
                          example: enabled
                        type:
                          type: string
                          description: 'User category'
                          enum:
                            - user
                            - pickup_line
                          example: user
                        language:
                          type: string
                          description: 'Preferred UI language'
                          enum:
                            - en
                            - de
                            - fr
                          example: en
                        sync_source:
                          type: string
                          description: 'Provisioning origin'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                            - microsoft_entra
                          example: manual
                        vip:
                          type: boolean
                          description: 'Whether the user is flagged as VIP'
                          example: false
                        show_in_address_book:
                          type: boolean
                          description: 'Whether the user appears in the shared address book'
                          example: true
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Default outbound CID for this user'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        caller_identity_internal_extension_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension shown as the internal caller ID'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        caller_identity_external_extension_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension shown as the external caller ID'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        allow_telephony:
                          type: boolean
                          description: 'Whether the user can place and receive calls'
                          example: true
                        allow_call_forwarding:
                          type: boolean
                          example: true
                        allow_change_twinning_dest:
                          type: boolean
                          description: 'Whether the user may change their twinning destination'
                          example: true
                        allow_dnd:
                          type: boolean
                          description: 'Whether the user may set their own Do Not Disturb'
                          example: true
                        allow_status_changer:
                          type: boolean
                          description: "Whether the user may change other users' statuses"
                          example: false
                        allow_anonymous_calls:
                          type: boolean
                          description: 'Whether the user is allowed to place anonymous outbound calls'
                          example: false
                        allow_international_calls:
                          type: boolean
                          example: false
                        allow_eu_calls:
                          type: boolean
                          example: true
                        allow_national_calls:
                          type: boolean
                          example: true
                        allow_premium_numbers:
                          type: boolean
                          example: false
                        allow_sms:
                          type: boolean
                          example: false
                        allow_manage_global_contacts:
                          type: boolean
                          example: false
                        allow_manage_voicemail_parameters:
                          type: boolean
                          example: true
                        allow_in_call_recording:
                          type: boolean
                          description: 'Whether the user can start/stop recording during a call'
                          example: false
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: 'Whether the PBX default outbound numbers are usable by this user'
                          example: true
                        allow_grafana_access:
                          type: boolean
                          description: 'Whether the user can access the Grafana dashboards'
                          example: false
                        allow_right_to_disconnect:
                          type: boolean
                          description: 'Whether the user may set their own right-to-disconnect schedule'
                          example: true
                        right_to_disconnect:
                          type: boolean
                          description: 'Whether the right-to-disconnect rule is currently enforced'
                          example: false
                        concurrent_calls:
                          type: boolean
                          description: 'Whether the user may have multiple simultaneous calls'
                          example: true
                        extension_roaming:
                          type: boolean
                          description: 'Whether the user may hot-desk by logging into other devices'
                          example: true
                        record_your_calls:
                          type: boolean
                          description: 'Default per-call recording flag for outbound external calls'
                          example: false
                        record_your_internal_calls:
                          type: integer
                          description: |
                            Tri-state flag controlling internal-call recording (0 = off, 1 = on,
                            2 = follow PBX default). Stored as an integer despite the boolean-style
                            name.
                          example: 2
                        access_all_call_recordings:
                          type: boolean
                          description: 'Whether the user may access call recordings of others'
                          example: false
                        call_recordings_visibility:
                          type: string
                          enum:
                            - all_calls
                            - own_calls_only
                          example: own_calls_only
                        call_information_visibility:
                          type: string
                          enum:
                            - none
                            - own_calls
                            - own_group_only
                          example: own_calls
                        send_missed_call_via_email:
                          type: boolean
                          example: true
                        limit_email_missed_call_to_direct:
                          type: boolean
                          description: 'Whether missed-call emails are limited to directly-dialled calls'
                          example: false
                        show_caller_id_for_twinning_call:
                          type: integer
                          description: |
                            Tri-state flag controlling caller-ID display on twinning calls (0 = off,
                            1 = on, 2 = follow PBX default).
                          example: 2
                        voicemail_type:
                          type: string
                          description: 'Voicemail mode'
                          enum:
                            - disabled
                            - enabled
                            - internal
                            - external
                          example: internal
                        voicemail_destination:
                          type: string
                          description: 'Where voicemail notifications are sent'
                          enum:
                            - email_only
                            - email_and_phone
                          example: email_only
                        invited_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When the user was invited (if onboarding via invitation)'
                          example: null
                        accepted_invitation_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When the user accepted their invitation'
                          example: null
                        email_verified_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-02-15T10:00:00Z'
                          readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        extensions:
                          type: array
                          description: 'Extensions owned by the user. Returned only when requested via `?include=extensions`.'
                          items:
                            type: object
                            description: |
                              Internal dial number assigned to a user, device, queue, or other PBX entity.
                              Per-direction call recording is controlled by the two `record_*_calls` flags.
                              The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                              (always present); the full `assigned_to` object is opt-in.
                            required:
                              - id
                              - pbx_id
                              - number
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Extension identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              assigned_to_type:
                                type:
                                  - string
                                  - 'null'
                                description: 'Friendly type of the entity this extension is assigned to'
                                enum:
                                  - user
                                  - sip_device
                                  - famulor_agent
                                example: user
                              assigned_to_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Identifier of the entity this extension is assigned to'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow applied to external inbound calls hitting this extension'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow applied to internal calls hitting this extension'
                                example: 550e8400-e29b-41d4-a716-446655440004
                              number:
                                type: string
                                maxLength: 16
                                description: 'Dialable extension digits'
                                example: '1337'
                              name:
                                type:
                                  - string
                                  - 'null'
                                description: 'Display name for the extension'
                                example: 'Support line'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Front-line support line'
                              record_external_calls:
                                type: boolean
                                description: 'Whether external calls on this extension are recorded'
                                example: true
                              record_internal_calls:
                                type: boolean
                                description: 'Whether internal calls on this extension are recorded'
                                example: false
                              sync_source:
                                type: string
                                description: 'Provisioning origin (cast to ExtensionSyncSource)'
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                example: manual
                              full_name_with_extension_number:
                                type:
                                  - string
                                  - 'null'
                                description: "Convenience label combining the assignee's name and the extension number"
                                example: 'Jane Smith (1337)'
                                readOnly: true
                              assigned_to:
                                type: object
                                description: |
                                  The resolved owner of this extension; shape varies by `assigned_to_type`.
                                  Returned only when requested via `?include=user` (or `?include=sipDevice`
                                  / `?include=famulorAgent`).
                              employee_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: |
                                  Identifier of the employee record linked to the assigned user.
                                  Returned only when requested via `?include=user.employee`.
                                example: 550e8400-e29b-41d4-a716-446655440005
                              department_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: |
                                  Department of the assigned user's employee, taken from their currently
                                  active contract (null when the employee has no active contract).
                                  Returned only when requested via `?include=user.employee`.
                                example: 550e8400-e29b-41d4-a716-446655440006
                              is_favorite:
                                type: boolean
                                description: |
                                  Whether the extension's user is one of the **calling user's** favourites.
                                  PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                                  OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        groups:
                          type: array
                          description: 'Groups the user belongs to. Returned only when requested via `?include=groups`.'
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        allow_manage_group_contacts:
                          type: array
                          description: |
                            Groups whose contacts the user may manage. Returned only when requested
                            via `?include=allowManageGroupContacts`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        allow_access_to_group_contacts:
                          type: array
                          description: |
                            Groups whose contacts the user may access. Returned only when requested
                            via `?include=allowAccessToGroupContacts`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        sip_devices:
                          type: array
                          description: 'SIP devices assigned to the user. Returned only when requested via `?include=sipDevices`.'
                          items:
                            type: object
                            description: |
                              Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                              against the PBX. The device owner is exposed as a friendly `target_type`
                              (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                              The SIP password is never exposed.
                            required:
                              - id
                              - pbx_id
                              - name
                              - is_enabled
                              - type
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'SIP device identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              target_type:
                                type:
                                  - string
                                  - 'null'
                                description: 'Friendly type of the entity the device is assigned to'
                                enum:
                                  - user
                                  - extension
                                example: user
                              target_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Identifier of the target entity'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_for_internal_calls:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Extension displayed in the device's caller ID for internal calls"
                                example: null
                              roaming_user_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'User currently roamed onto this device'
                                example: null
                              location_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Physical location the device is installed at'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              parent_sip_device_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                                example: null
                              name:
                                type: string
                                maxLength: 128
                                example: 'Reception desk phone'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Front-desk Yealink T46U'
                              is_enabled:
                                type: boolean
                                description: 'Whether the device is currently enabled'
                                example: true
                              ip_internal:
                                type:
                                  - string
                                  - 'null'
                                description: 'Last-seen internal IP'
                                example: 192.168.1.42
                              ip_external:
                                type:
                                  - string
                                  - 'null'
                                description: 'Last-seen external IP'
                                example: 203.0.113.10
                              user_agent:
                                type:
                                  - string
                                  - 'null'
                                description: 'SIP User-Agent string reported by the device'
                                example: 'Yealink SIP-T46U 108.86.0.10'
                              mac:
                                type:
                                  - string
                                  - 'null'
                                description: 'MAC address'
                                example: '00:0a:95:9d:68:16'
                              vlan_phone:
                                type:
                                  - integer
                                  - 'null'
                                description: 'VLAN id for the phone interface'
                                example: 100
                              vlan_pc:
                                type:
                                  - integer
                                  - 'null'
                                description: 'VLAN id for the PC pass-through interface'
                                example: 200
                              sip_username:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 24
                                description: 'SIP authentication username'
                                example: device_001
                              alt_username:
                                type:
                                  - string
                                  - 'null'
                                description: 'Alternate SIP username (used for multi-line registrations)'
                                example: null
                              transport:
                                type: string
                                description: 'SIP transport'
                                enum:
                                  - udp
                                  - tcp
                                  - tls
                                example: tls
                              type:
                                type: string
                                description: 'Device provisioning category'
                                enum:
                                  - auto
                                  - manual
                                  - gigaset
                                  - trunk
                                example: auto
                              allow_roaming:
                                type: boolean
                                description: 'Whether the device accepts roamed-in users'
                                example: false
                              language:
                                type: string
                                description: 'Display language for the device'
                                example: en
                              easy_deploy:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp until which the device is in easy-deploy mode'
                                example: null
                              notify:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp at which a SIP NOTIFY was last requested'
                                example: null
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: 'Whether the PBX default outbound numbers are usable from this device'
                                example: false
                              sync_source:
                                type: string
                                description: 'Provisioning origin'
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                example: provision
                              custom_provisioning:
                                type:
                                  - string
                                  - 'null'
                                description: 'Custom provisioning template snippet'
                                example: null
                              last_seen:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Last time the device registered'
                                example: '2024-03-01T08:29:07Z'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              target:
                                type: object
                                description: |
                                  The resolved device owner (a user or an extension); shape varies by
                                  `target_type`. Returned only when requested via `?include=target`.
                              tags:
                                type: array
                                description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                                items:
                                  type: object
                                  description: |
                                    Free-form label that can be attached to users, SIP devices, phone numbers, and
                                    other tenant resources for grouping, filtering, and reporting. Tags are scoped
                                    to a single Pbx (tenant). Associations to the resources a tag is applied to are
                                    held on the relevant pivot tables, not on this schema.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                      readOnly: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                      example: 'VIP Customers'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                      example: 'Customers with priority routing and dedicated agents.'
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              caller_identities:
                                type: array
                                description: |
                                  Caller identities available to this device. Returned only when requested
                                  via `?include=callerIdentities`.
                                items:
                                  type: object
                              location:
                                description: |
                                  The resolved installation location. Returned only when requested via
                                  `?include=location`.
                                allOf:
                                  -
                                    type: object
                                    description: |
                                      Physical office or site associated with a PBX. Locations form a nested-set
                                      tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                      used for emergency call routing.
                                    required:
                                      - id
                                      - pbx_id
                                      - name
                                    properties:
                                      id:
                                        type: string
                                        format: uuid
                                        description: 'Location identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440000
                                        readOnly: true
                                      pbx_id:
                                        type: string
                                        format: uuid
                                        description: 'Pbx identifier (tenant)'
                                        example: 550e8400-e29b-41d4-a716-446655440001
                                      company_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Owning company identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440004
                                      parent_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Parent location identifier in the nested-set tree'
                                        example: 550e8400-e29b-41d4-a716-446655440002
                                      name:
                                        type: string
                                        maxLength: 64
                                        example: 'Luxembourg HQ'
                                      description:
                                        type:
                                          - string
                                          - 'null'
                                        maxLength: 255
                                        example: 'Main office, 5th floor'
                                      street_no:
                                        type:
                                          - string
                                          - 'null'
                                        description: 'Street number portion of the address'
                                        example: '12'
                                      street:
                                        type:
                                          - string
                                          - 'null'
                                        example: 'Main Street'
                                      city:
                                        type:
                                          - string
                                          - 'null'
                                        example: Luxembourg
                                      postal:
                                        type:
                                          - string
                                          - 'null'
                                        description: 'Postal code'
                                        example: '1234'
                                      country_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Country identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440003
                                      lft:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Nested-set left bound'
                                        example: 1
                                      rgt:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Nested-set right bound'
                                        example: 10
                                      depth:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Tree depth (0 for root locations)'
                                        example: 0
                                      enable_location_as_presence_status:
                                        type: boolean
                                        description: 'Whether this location can be used as a presence status value'
                                        example: false
                                      style:
                                        type:
                                          - object
                                          - 'null'
                                        description: 'Optional presentation style (badge icon and colours) for the location'
                                        example:
                                          icon_class: la-map-pin
                                          bg_color: '#3490dc'
                                          font_color: '#ffffff'
                                      is_fixed_location:
                                        type: boolean
                                        description: 'Whether this is a fixed (geofenced) physical location'
                                        example: true
                                      latitude:
                                        type:
                                          - number
                                          - 'null'
                                        format: float
                                        description: 'Latitude of the location, in decimal degrees'
                                        example: 49.6116
                                      longitude:
                                        type:
                                          - number
                                          - 'null'
                                        format: float
                                        description: 'Longitude of the location, in decimal degrees'
                                        example: 6.1319
                                      geofence_radius_m:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Geofence radius around the location, in metres'
                                        example: 100
                                      created_at:
                                        type:
                                          - string
                                          - 'null'
                                        format: date-time
                                        example: '2024-03-01T08:29:07Z'
                                        readOnly: true
                                      updated_at:
                                        type:
                                          - string
                                          - 'null'
                                        format: date-time
                                        example: '2024-03-01T08:29:07Z'
                                        readOnly: true
                        twinnings:
                          type: array
                          description: 'Twinnings configured for the user. Returned only when requested via `?include=twinnings`.'
                          items:
                            type: object
                            description: |
                              Twinning: an external destination that rings alongside a user's extension
                              (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                              the twinned destination rings in parallel so the call can be answered away
                              from the desk phone. Tenant scoping is derived from the attached user; this
                              resource has no direct `pbx_id` column of its own.
                            required:
                              - id
                              - user_id
                              - status
                              - phone_number
                              - delay
                              - sync_source
                              - type
                              - dial_strategy
                              - fmc_enabled
                              - backup_phone_number
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique identifier of the twinning.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              user_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              status:
                                type: string
                                enum:
                                  - enabled
                                  - disabled
                                description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                                example: enabled
                              phone_number:
                                type:
                                  - string
                                  - 'null'
                                description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                                example: '+12125550100'
                              delay:
                                type: integer
                                format: int32
                                minimum: 0
                                description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                                example: 5
                              sync_source:
                                type: string
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                                example: manual
                              type:
                                type: string
                                enum:
                                  - mobile
                                  - teams
                                description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                                example: mobile
                              dial_strategy:
                                type: string
                                enum:
                                  - gsm_only
                                  - voip_only
                                  - voip_and_gsm_fallback
                                description: |
                                  How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                                  `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                                  VoIP first and falls back to GSM. Only meaningful for mobile-type
                                  twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                                example: voip_and_gsm_fallback
                              fmc_enabled:
                                type: boolean
                                description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                                example: false
                              backup_phone_number:
                                type:
                                  - string
                                  - 'null'
                                description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                                example: '+12125550101'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        caller_identities:
                          type: array
                          description: |
                            Effective (inherited) caller identities for the user: own plus those of
                            the user's groups plus the PBX's. Returned only when requested via
                            `?include=callerIdentities`.
                          items:
                            type: object
                        locations:
                          type: array
                          description: 'Locations the user is associated with. Returned only when requested via `?include=locations`.'
                          items:
                            type: object
                            description: |
                              Physical office or site associated with a PBX. Locations form a nested-set
                              tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                              used for emergency call routing.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Location identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              company_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Owning company identifier'
                                example: 550e8400-e29b-41d4-a716-446655440004
                              parent_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Parent location identifier in the nested-set tree'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              name:
                                type: string
                                maxLength: 64
                                example: 'Luxembourg HQ'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Main office, 5th floor'
                              street_no:
                                type:
                                  - string
                                  - 'null'
                                description: 'Street number portion of the address'
                                example: '12'
                              street:
                                type:
                                  - string
                                  - 'null'
                                example: 'Main Street'
                              city:
                                type:
                                  - string
                                  - 'null'
                                example: Luxembourg
                              postal:
                                type:
                                  - string
                                  - 'null'
                                description: 'Postal code'
                                example: '1234'
                              country_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Country identifier'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              lft:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Nested-set left bound'
                                example: 1
                              rgt:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Nested-set right bound'
                                example: 10
                              depth:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Tree depth (0 for root locations)'
                                example: 0
                              enable_location_as_presence_status:
                                type: boolean
                                description: 'Whether this location can be used as a presence status value'
                                example: false
                              style:
                                type:
                                  - object
                                  - 'null'
                                description: 'Optional presentation style (badge icon and colours) for the location'
                                example:
                                  icon_class: la-map-pin
                                  bg_color: '#3490dc'
                                  font_color: '#ffffff'
                              is_fixed_location:
                                type: boolean
                                description: 'Whether this is a fixed (geofenced) physical location'
                                example: true
                              latitude:
                                type:
                                  - number
                                  - 'null'
                                format: float
                                description: 'Latitude of the location, in decimal degrees'
                                example: 49.6116
                              longitude:
                                type:
                                  - number
                                  - 'null'
                                format: float
                                description: 'Longitude of the location, in decimal degrees'
                                example: 6.1319
                              geofence_radius_m:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Geofence radius around the location, in metres'
                                example: 100
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        languages:
                          type: array
                          description: 'Languages the user is associated with. Returned only when requested via `?include=languages`.'
                          items:
                            type: object
                            description: |
                              A language defined for the tenant, used to label sound files, voice prompts
                              (IVR announcements), and per-user language preferences. Each language belongs
                              to exactly one Pbx (tenant) and is identified by a free-text name.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique language identifier (UUID).'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this language.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable language name as shown in the cockpit and selectors.'
                                example: English
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        tags:
                          type: array
                          description: 'Tags attached to the user. Returned only when requested via `?include=tags`.'
                          items:
                            type: object
                            description: |
                              Free-form label that can be attached to users, SIP devices, phone numbers, and
                              other tenant resources for grouping, filtering, and reporting. Tags are scoped
                              to a single Pbx (tenant). Associations to the resources a tag is applied to are
                              held on the relevant pivot tables, not on this schema.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                example: 'VIP Customers'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                example: 'Customers with priority routing and dedicated agents.'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        queues:
                          type: array
                          description: 'Queues the user is a member of. Returned only when requested via `?include=queues`.'
                          items:
                            type: object
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /schedules:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'List schedules'
      operationId: listSchedules
      description: |
        Returns a paginated list of the calling PBX's schedules. Requires the
        `schedules` scope on an Integrations API key (a user bearer token also
        passes). Multi-tenant scoping is enforced: only the caller's own schedules
        are ever returned, and no query parameter can widen that.

        Results are sorted by `name` ascending unless `sort` says otherwise. Page
        size is `per_page`, capped at 100, which is also the default. Schedule steps
        (the time rules) are not embedded.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Items per page. Values above the maximum, or below 1, fall back to the maximum.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by, `-` prefixed for descending. Allowed: `name`,
            `created_at`. Anything else responds 400.
          schema:
            type: string
            enum:
              - name
              - '-name'
              - created_at
              - '-created_at'
          example: '-created_at'
        -
          name: 'filter[name]'
          in: query
          required: false
          description: 'Partial, case-insensitive match on the schedule name.'
          schema:
            type: string
          example: business
        -
          name: 'filter[description]'
          in: query
          required: false
          description: 'Partial, case-insensitive match on the schedule description.'
          schema:
            type: string
          example: holiday
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Named schedule belonging to a single tenant (Pbx). A schedule groups a set of
                        time-of-day rules that downstream call flows reference to decide routing based
                        on the current date and time (for example, open versus closed hours). The
                        actual rules live on the related `ScheduleStep` records (one schedule may
                        contain many steps covering days-of-the-week, fixed dates, recurring dates, or
                        specific periods); those steps are not embedded in this response and are
                        retrieved through their own endpoints.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the schedule.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the owning tenant (Pbx). Every schedule is scoped to exactly one tenant.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type: string
                          maxLength: 255
                          description: 'Human-readable label for the schedule, shown in the cockpit and used when selecting the schedule in call flows.'
                          example: 'Business hours'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Optional free-text note describing the purpose or coverage of the schedule. Null when no description was provided.'
                          example: 'Monday to Friday, 09:00 to 18:00'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the schedule was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the schedule was last modified.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    name: 'Business hours'
                    description: 'Monday to Friday, 09:00 to 18:00'
                    created_at: '2024-03-01T08:29:07.000000Z'
                    updated_at: '2024-03-01T08:29:07.000000Z'
                  -
                    id: 550e8400-e29b-41d4-a716-446655440002
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    name: 'Holiday schedule'
                    description: null
                    created_at: '2024-03-04T11:02:55.000000Z'
                    updated_at: '2024-05-19T09:41:12.000000Z'
                links:
                  first: 'https://cockpit.voxbi.com/api/v1/schedules?page=1'
                  last: 'https://cockpit.voxbi.com/api/v1/schedules?page=1'
                  prev: null
                  next: null
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  path: 'https://cockpit.voxbi.com/api/v1/schedules'
                  per_page: 100
                  to: 2
                  total: 2
        400:
          description: |
            Bad Request. A `filter[...]` key or a `sort` field that the endpoint does not
            allow was requested. The message names the allowed values. Nothing is returned
            and no partial result is produced: correct the query string and retry.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              examples:
                invalidFilter:
                  summary: 'Unsupported filter key'
                  value:
                    message: 'Requested filter(s) `owner` are not allowed. Allowed filter(s) are `name, description`.'
                invalidSort:
                  summary: 'Unsupported sort field'
                  value:
                    message: 'Requested sort(s) `description` is not allowed. Allowed sort(s) are `name, created_at`.'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
    post:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'Create a schedule'
      operationId: createSchedule
      description: |
        Creates a schedule for the calling PBX. Requires the `schedules` scope on an
        Integrations API key (a user bearer token also passes).

        The schedule is the container only: the time rules themselves (days of the
        week, fixed dates, recurring dates, specific periods) are `ScheduleStep`
        records and are still managed in the cockpit, so a schedule created here
        starts out with no steps and matches nothing until steps are added.

        `pbx_id` is forced from the authenticated principal (a user's PBX, or the
        Pbx-owned API key itself) and is never read from the request body: sending
        another tenant's id has no effect. Schedule names are not required to be
        unique within a PBX.

        The response is the created schedule, unwrapped (no `data` envelope), and is
        identical to what a subsequent GET of the same id returns.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - name
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: 'Human-readable label for the schedule, shown in the cockpit and when selecting the schedule in a call flow.'
                  example: 'Business hours'
                description:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional free-text note describing the purpose or coverage of the schedule. Omit or send null for none.'
                  example: 'Monday to Friday, 09:00 to 18:00'
            examples:
              full:
                summary: 'Name and description'
                value:
                  name: 'Business hours'
                  description: 'Monday to Friday, 09:00 to 18:00'
              minimal:
                summary: 'Name only (description omitted, stored as null)'
                value:
                  name: 'Holiday schedule'
      responses:
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Named schedule belonging to a single tenant (Pbx). A schedule groups a set of
                  time-of-day rules that downstream call flows reference to decide routing based
                  on the current date and time (for example, open versus closed hours). The
                  actual rules live on the related `ScheduleStep` records (one schedule may
                  contain many steps covering days-of-the-week, fixed dates, recurring dates, or
                  specific periods); those steps are not embedded in this response and are
                  retrieved through their own endpoints.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the schedule.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the owning tenant (Pbx). Every schedule is scoped to exactly one tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 255
                    description: 'Human-readable label for the schedule, shown in the cockpit and used when selecting the schedule in call flows.'
                    example: 'Business hours'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note describing the purpose or coverage of the schedule. Null when no description was provided.'
                    example: 'Monday to Friday, 09:00 to 18:00'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was last modified.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                name: 'Business hours'
                description: 'Monday to Friday, 09:00 to 18:00'
                created_at: '2024-03-01T08:29:07.000000Z'
                updated_at: '2024-03-01T08:29:07.000000Z'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        422:
          description: |
            Unprocessable Entity. The request body failed validation. `errors` maps each
            rejected field to its messages, and `message` repeats the first one. Nothing
            was written.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: 'The first validation message, repeated for convenience.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        items:
                          type: string
                      description:
                        type: array
                        items:
                          type: string
              examples:
                nameMissing:
                  summary: 'name omitted'
                  value:
                    message: 'The name field is required.'
                    errors:
                      name:
                        - 'The name field is required.'
                tooLong:
                  summary: 'Fields over their maximum length'
                  value:
                    message: 'The name field may not be greater than 255 characters.'
                    errors:
                      name:
                        - 'The name field may not be greater than 255 characters.'
                      description:
                        - 'The description field may not be greater than 255 characters.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
  '/schedules/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'Get a schedule'
      operationId: getSchedule
      description: |
        Returns the schedule identified by the path parameter, unwrapped (no `data`
        envelope). Requires the `schedules` scope on an Integrations API key (a user
        bearer token also passes).

        Multi-tenant scoping is enforced: a schedule belonging to another PBX returns
        the same 404 as an id that does not exist anywhere, so the endpoint never
        confirms a foreign schedule. Schedule steps are not embedded.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Schedule identifier'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Named schedule belonging to a single tenant (Pbx). A schedule groups a set of
                  time-of-day rules that downstream call flows reference to decide routing based
                  on the current date and time (for example, open versus closed hours). The
                  actual rules live on the related `ScheduleStep` records (one schedule may
                  contain many steps covering days-of-the-week, fixed dates, recurring dates, or
                  specific periods); those steps are not embedded in this response and are
                  retrieved through their own endpoints.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the schedule.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the owning tenant (Pbx). Every schedule is scoped to exactly one tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 255
                    description: 'Human-readable label for the schedule, shown in the cockpit and used when selecting the schedule in call flows.'
                    example: 'Business hours'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note describing the purpose or coverage of the schedule. Null when no description was provided.'
                    example: 'Monday to Friday, 09:00 to 18:00'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was last modified.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                name: 'Business hours'
                description: 'Monday to Friday, 09:00 to 18:00'
                created_at: '2024-03-01T08:29:07.000000Z'
                updated_at: '2024-03-01T08:29:07.000000Z'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        404:
          description: |
            Not Found. No schedule with that id exists inside the caller's PBX. A schedule
            that belongs to another tenant returns exactly this response, so the endpoint
            never reveals whether a foreign id exists.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Schedule not found.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
    put:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'Update a schedule'
      operationId: updateSchedule
      description: |
        Updates the schedule identified by the path parameter. Requires the
        `schedules` scope on an Integrations API key (a user bearer token also
        passes).

        This is a full replace and takes the same body as creation, so `name` stays
        required and an omitted `description` is CLEARED (set to null). Use `PATCH`
        on the same path when you want to change one field and leave the rest alone.

        Multi-tenant scoping is enforced, so a schedule belonging to another PBX
        responds 404 and is left untouched. `pbx_id` is forced from the authenticated
        principal and is never read from the body, so a schedule cannot be moved
        between tenants.

        Only the schedule record is affected. Its steps (the time rules) are managed
        in the cockpit and are unchanged by this call. The response is the updated
        schedule, unwrapped (no `data` envelope).
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Schedule identifier'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - name
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: 'Human-readable label for the schedule.'
                  example: 'Business hours (winter)'
                description:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional free-text note. Omit or send null to clear it.'
                  example: 'Monday to Friday, 09:00 to 17:00'
            examples:
              rename:
                summary: 'Rename and re-describe'
                value:
                  name: 'Business hours (winter)'
                  description: 'Monday to Friday, 09:00 to 17:00'
              clearDescription:
                summary: 'Clear the description by omitting it'
                value:
                  name: 'Business hours'
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Named schedule belonging to a single tenant (Pbx). A schedule groups a set of
                  time-of-day rules that downstream call flows reference to decide routing based
                  on the current date and time (for example, open versus closed hours). The
                  actual rules live on the related `ScheduleStep` records (one schedule may
                  contain many steps covering days-of-the-week, fixed dates, recurring dates, or
                  specific periods); those steps are not embedded in this response and are
                  retrieved through their own endpoints.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the schedule.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the owning tenant (Pbx). Every schedule is scoped to exactly one tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 255
                    description: 'Human-readable label for the schedule, shown in the cockpit and used when selecting the schedule in call flows.'
                    example: 'Business hours'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note describing the purpose or coverage of the schedule. Null when no description was provided.'
                    example: 'Monday to Friday, 09:00 to 18:00'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was last modified.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                name: 'Business hours (winter)'
                description: 'Monday to Friday, 09:00 to 17:00'
                created_at: '2024-03-01T08:29:07.000000Z'
                updated_at: '2024-11-04T10:15:44.000000Z'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        404:
          description: |
            Not Found. No schedule with that id exists inside the caller's PBX. A schedule
            that belongs to another tenant returns exactly this response, so the endpoint
            never reveals whether a foreign id exists.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Schedule not found.'
        422:
          description: |
            Unprocessable Entity. The request body failed validation. `errors` maps each
            rejected field to its messages, and `message` repeats the first one. Nothing
            was written.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: 'The first validation message, repeated for convenience.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        items:
                          type: string
                      description:
                        type: array
                        items:
                          type: string
              examples:
                nameMissing:
                  summary: 'name omitted'
                  value:
                    message: 'The name field is required.'
                    errors:
                      name:
                        - 'The name field is required.'
                tooLong:
                  summary: 'Fields over their maximum length'
                  value:
                    message: 'The name field may not be greater than 255 characters.'
                    errors:
                      name:
                        - 'The name field may not be greater than 255 characters.'
                      description:
                        - 'The description field may not be greater than 255 characters.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
    patch:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'Partially update a schedule'
      operationId: patchSchedule
      description: |
        Partially updates the schedule identified by the path parameter. Requires the
        `schedules` scope on an Integrations API key (a user bearer token also
        passes).

        Unlike `PUT`, every field is optional and anything absent from the body is
        left exactly as it was: send only `description` to re-note a schedule without
        touching its name. A field that IS present is still validated, so `name`
        cannot be blanked. Send `description: null` to clear the note.

        Same tenant rules as `PUT`: `pbx_id` is forced from the authenticated
        principal, and another PBX's schedule responds 404 and is left untouched.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Schedule identifier'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        description: 'At least one field. Anything omitted is left unchanged.'
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              minProperties: 1
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: 'Human-readable label for the schedule. Omit to keep the current name; it may not be sent empty.'
                description:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Free-text note. Omit to keep the current note, or send null to clear it.'
            examples:
              descriptionOnly:
                summary: 'Re-note without touching the name'
                value:
                  description: 'Monday to Friday, 09:00 to 17:00'
              nameOnly:
                summary: 'Rename without touching the note'
                value:
                  name: 'Business hours (winter)'
              clearDescription:
                summary: 'Clear the note explicitly'
                value:
                  description: null
      responses:
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Named schedule belonging to a single tenant (Pbx). A schedule groups a set of
                  time-of-day rules that downstream call flows reference to decide routing based
                  on the current date and time (for example, open versus closed hours). The
                  actual rules live on the related `ScheduleStep` records (one schedule may
                  contain many steps covering days-of-the-week, fixed dates, recurring dates, or
                  specific periods); those steps are not embedded in this response and are
                  retrieved through their own endpoints.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the schedule.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the owning tenant (Pbx). Every schedule is scoped to exactly one tenant.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type: string
                    maxLength: 255
                    description: 'Human-readable label for the schedule, shown in the cockpit and used when selecting the schedule in call flows.'
                    example: 'Business hours'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note describing the purpose or coverage of the schedule. Null when no description was provided.'
                    example: 'Monday to Friday, 09:00 to 18:00'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the schedule was last modified.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                name: 'Business hours'
                description: 'Monday to Friday, 09:00 to 17:00'
                created_at: '2024-03-01T08:29:07.000000Z'
                updated_at: '2024-11-04T10:15:44.000000Z'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        404:
          description: |
            Not Found. No schedule with that id exists inside the caller's PBX. A schedule
            that belongs to another tenant returns exactly this response, so the endpoint
            never reveals whether a foreign id exists.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Schedule not found.'
        422:
          description: |
            Unprocessable Entity. The request body failed validation. `errors` maps each
            rejected field to its messages, and `message` repeats the first one. Nothing
            was written.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: 'The first validation message, repeated for convenience.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        items:
                          type: string
                      description:
                        type: array
                        items:
                          type: string
              examples:
                nameMissing:
                  summary: 'name omitted'
                  value:
                    message: 'The name field is required.'
                    errors:
                      name:
                        - 'The name field is required.'
                tooLong:
                  summary: 'Fields over their maximum length'
                  value:
                    message: 'The name field may not be greater than 255 characters.'
                    errors:
                      name:
                        - 'The name field may not be greater than 255 characters.'
                      description:
                        - 'The description field may not be greater than 255 characters.'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
    delete:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Schedules
      summary: 'Delete a schedule'
      operationId: deleteSchedule
      description: |
        Soft-deletes the schedule identified by the path parameter, together with its
        steps. Requires the `schedules` scope on an Integrations API key (a user
        bearer token also passes). There is no response body.

        A schedule that is still wired into a live call flow is NOT deleted: the
        request fails with 409 and lists the call flows that still route through it,
        because removing the schedule would silently change inbound routing. Unwire
        it from those call-flow steps first, then retry. A schedule referenced only by
        trashed steps or trashed call flows deletes normally.

        On success the schedule disappears from this API immediately (list and get
        both stop returning it) but an administrator can still restore it, with its
        steps, from the cockpit trash.

        Multi-tenant scoping is enforced: a schedule belonging to another PBX responds
        404 and is left untouched, and another tenant's call flows never affect the
        usage check nor appear in the 409 body.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'Schedule identifier'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        204:
          description: 'Deleted. No content.'
        401:
          description: |
            Unauthenticated. The `Authorization: Bearer <token>` header was missing,
            malformed, or names a token that has been revoked or deleted.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: Unauthenticated.
        403:
          description: |
            Forbidden. The bearer token authenticated successfully but does not carry the
            scope this endpoint requires. Re-create the Integrations API key with the
            missing scope selected (Integrations > New integration > API key).
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Missing scope'
                properties:
                  message:
                    type: string
              example:
                message: 'Invalid ability provided.'
        404:
          description: |
            Not Found. No schedule with that id exists inside the caller's PBX. A schedule
            that belongs to another tenant returns exactly this response, so the endpoint
            never reveals whether a foreign id exists.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Schedule not found.'
        409:
          description: |
            Conflict. The schedule is still wired into at least one live call flow, so it
            was not deleted and nothing changed. `call_flows` names every call flow that
            still routes through it: remove the schedule from those call-flow steps (in the
            cockpit) and retry.
          headers:
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                description: 'Schedule still in use'
                properties:
                  message:
                    type: string
                    description: 'Human-readable reason, including how many call flows still use the schedule.'
                  call_flows:
                    type: array
                    description: 'The live call flows still referencing this schedule.'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
              example:
                message: 'This schedule is still used by 2 call flow(s) and cannot be deleted. Remove it from those call flows first.'
                call_flows:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440010
                    name: 'After hours'
                  -
                    id: 550e8400-e29b-41d4-a716-446655440011
                    name: 'Sales routing'
        429:
          description: |
            Too Many Requests. The rate limit for this action has been exceeded. Retry
            after the window indicated by the Retry-After header.
          headers:
            Retry-After:
              description: 'Seconds to wait before retrying.'
              schema:
                type: integer
                example: 60
            Content-Type:
              schema:
                type: string
                example: application/json
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Too Many Attempts.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
  /sip-carriers:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SipCarriers
      summary: 'List SIP carrier'
      operationId: listSipCarriers
      description: |
        Returns a paginated list of sip carriers. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `sip_user`, `sip_registrar`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Upstream SIP trunk used for outbound calls and number termination.
                      required:
                        - id
                        - pbx_id
                        - sip_registrar
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'SIP carrier identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type:
                            - string
                            - 'null'
                          maxLength: 128
                          example: 'Primary carrier'
                        sip_user:
                          type:
                            - string
                            - 'null'
                          maxLength: 64
                          description: 'SIP authentication username'
                          example: trunk_user
                        sip_registrar:
                          type: string
                          maxLength: 64
                          description: 'SIP registrar hostname or IP'
                          example: sip.carrier.example.com
                        register:
                          type: boolean
                          description: 'Whether the PBX registers against this carrier'
                          example: true
                        destination_header:
                          type: string
                          description: 'SIP header consulted to determine the called party'
                          enum:
                            - default
                            - p-called-party-id
                            - to
                          example: default
                        incoming_header:
                          type: string
                          description: 'SIP header consulted to identify incoming calls'
                          enum:
                            - request-uri
                            - to
                            - contact
                          example: request-uri
                        dtmf_mode:
                          type: string
                          description: 'DTMF transport mode for calls through this carrier'
                          enum:
                            - info
                            - rfc4733
                            - inband
                            - auto
                          example: rfc4733
                        display_name:
                          type:
                            - string
                            - 'null'
                          description: 'Convenience label combining the carrier name and registrar'
                          example: 'Primary carrier (sip.carrier.example.com)'
                          readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/sip-carriers/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SipCarriers
      summary: 'Get a sIP Carrier'
      operationId: getSipCarrier
      description: |
        Returns the sip carrier identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Upstream SIP trunk used for outbound calls and number termination.
                required:
                  - id
                  - pbx_id
                  - sip_registrar
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'SIP carrier identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  name:
                    type:
                      - string
                      - 'null'
                    maxLength: 128
                    example: 'Primary carrier'
                  sip_user:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    description: 'SIP authentication username'
                    example: trunk_user
                  sip_registrar:
                    type: string
                    maxLength: 64
                    description: 'SIP registrar hostname or IP'
                    example: sip.carrier.example.com
                  register:
                    type: boolean
                    description: 'Whether the PBX registers against this carrier'
                    example: true
                  destination_header:
                    type: string
                    description: 'SIP header consulted to determine the called party'
                    enum:
                      - default
                      - p-called-party-id
                      - to
                    example: default
                  incoming_header:
                    type: string
                    description: 'SIP header consulted to identify incoming calls'
                    enum:
                      - request-uri
                      - to
                      - contact
                    example: request-uri
                  dtmf_mode:
                    type: string
                    description: 'DTMF transport mode for calls through this carrier'
                    enum:
                      - info
                      - rfc4733
                      - inband
                      - auto
                    example: rfc4733
                  display_name:
                    type:
                      - string
                      - 'null'
                    description: 'Convenience label combining the carrier name and registrar'
                    example: 'Primary carrier (sip.carrier.example.com)'
                    readOnly: true
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /sip-devices:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SipDevices
      summary: 'List SIP device'
      operationId: listSipDevices
      description: |
        Returns a paginated list of sip devices. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `mac`, `sip_username`, `is_enabled`, `user_id`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
        -
          name: include
          description: |
            Comma-separated related resources to embed (dot-nested where
            shown). Allowed: `target`, `tags`, `callerIdentities`, `location`.
          in: query
          required: false
          schema:
            type: string
          example: 'target,tags'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                        against the PBX. The device owner is exposed as a friendly `target_type`
                        (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                        The SIP password is never exposed.
                      required:
                        - id
                        - pbx_id
                        - name
                        - is_enabled
                        - type
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'SIP device identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        target_type:
                          type:
                            - string
                            - 'null'
                          description: 'Friendly type of the entity the device is assigned to'
                          enum:
                            - user
                            - extension
                          example: user
                        target_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the target entity'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_for_internal_calls:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Extension displayed in the device's caller ID for internal calls"
                          example: null
                        roaming_user_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'User currently roamed onto this device'
                          example: null
                        location_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Physical location the device is installed at'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        parent_sip_device_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                          example: null
                        name:
                          type: string
                          maxLength: 128
                          example: 'Reception desk phone'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Front-desk Yealink T46U'
                        is_enabled:
                          type: boolean
                          description: 'Whether the device is currently enabled'
                          example: true
                        ip_internal:
                          type:
                            - string
                            - 'null'
                          description: 'Last-seen internal IP'
                          example: 192.168.1.42
                        ip_external:
                          type:
                            - string
                            - 'null'
                          description: 'Last-seen external IP'
                          example: 203.0.113.10
                        user_agent:
                          type:
                            - string
                            - 'null'
                          description: 'SIP User-Agent string reported by the device'
                          example: 'Yealink SIP-T46U 108.86.0.10'
                        mac:
                          type:
                            - string
                            - 'null'
                          description: 'MAC address'
                          example: '00:0a:95:9d:68:16'
                        vlan_phone:
                          type:
                            - integer
                            - 'null'
                          description: 'VLAN id for the phone interface'
                          example: 100
                        vlan_pc:
                          type:
                            - integer
                            - 'null'
                          description: 'VLAN id for the PC pass-through interface'
                          example: 200
                        sip_username:
                          type:
                            - string
                            - 'null'
                          maxLength: 24
                          description: 'SIP authentication username'
                          example: device_001
                        alt_username:
                          type:
                            - string
                            - 'null'
                          description: 'Alternate SIP username (used for multi-line registrations)'
                          example: null
                        transport:
                          type: string
                          description: 'SIP transport'
                          enum:
                            - udp
                            - tcp
                            - tls
                          example: tls
                        type:
                          type: string
                          description: 'Device provisioning category'
                          enum:
                            - auto
                            - manual
                            - gigaset
                            - trunk
                          example: auto
                        allow_roaming:
                          type: boolean
                          description: 'Whether the device accepts roamed-in users'
                          example: false
                        language:
                          type: string
                          description: 'Display language for the device'
                          example: en
                        easy_deploy:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp until which the device is in easy-deploy mode'
                          example: null
                        notify:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp at which a SIP NOTIFY was last requested'
                          example: null
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: 'Whether the PBX default outbound numbers are usable from this device'
                          example: false
                        sync_source:
                          type: string
                          description: 'Provisioning origin'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          example: provision
                        custom_provisioning:
                          type:
                            - string
                            - 'null'
                          description: 'Custom provisioning template snippet'
                          example: null
                        last_seen:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Last time the device registered'
                          example: '2024-03-01T08:29:07Z'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        target:
                          type: object
                          description: |
                            The resolved device owner (a user or an extension); shape varies by
                            `target_type`. Returned only when requested via `?include=target`.
                        tags:
                          type: array
                          description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                          items:
                            type: object
                            description: |
                              Free-form label that can be attached to users, SIP devices, phone numbers, and
                              other tenant resources for grouping, filtering, and reporting. Tags are scoped
                              to a single Pbx (tenant). Associations to the resources a tag is applied to are
                              held on the relevant pivot tables, not on this schema.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                example: 'VIP Customers'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                example: 'Customers with priority routing and dedicated agents.'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        caller_identities:
                          type: array
                          description: |
                            Caller identities available to this device. Returned only when requested
                            via `?include=callerIdentities`.
                          items:
                            type: object
                        location:
                          description: |
                            The resolved installation location. Returned only when requested via
                            `?include=location`.
                          allOf:
                            -
                              type: object
                              description: |
                                Physical office or site associated with a PBX. Locations form a nested-set
                                tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                used for emergency call routing.
                              required:
                                - id
                                - pbx_id
                                - name
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                  description: 'Location identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440000
                                  readOnly: true
                                pbx_id:
                                  type: string
                                  format: uuid
                                  description: 'Pbx identifier (tenant)'
                                  example: 550e8400-e29b-41d4-a716-446655440001
                                company_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Owning company identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440004
                                parent_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Parent location identifier in the nested-set tree'
                                  example: 550e8400-e29b-41d4-a716-446655440002
                                name:
                                  type: string
                                  maxLength: 64
                                  example: 'Luxembourg HQ'
                                description:
                                  type:
                                    - string
                                    - 'null'
                                  maxLength: 255
                                  example: 'Main office, 5th floor'
                                street_no:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Street number portion of the address'
                                  example: '12'
                                street:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Main Street'
                                city:
                                  type:
                                    - string
                                    - 'null'
                                  example: Luxembourg
                                postal:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Postal code'
                                  example: '1234'
                                country_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Country identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440003
                                lft:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Nested-set left bound'
                                  example: 1
                                rgt:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Nested-set right bound'
                                  example: 10
                                depth:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Tree depth (0 for root locations)'
                                  example: 0
                                enable_location_as_presence_status:
                                  type: boolean
                                  description: 'Whether this location can be used as a presence status value'
                                  example: false
                                style:
                                  type:
                                    - object
                                    - 'null'
                                  description: 'Optional presentation style (badge icon and colours) for the location'
                                  example:
                                    icon_class: la-map-pin
                                    bg_color: '#3490dc'
                                    font_color: '#ffffff'
                                is_fixed_location:
                                  type: boolean
                                  description: 'Whether this is a fixed (geofenced) physical location'
                                  example: true
                                latitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: float
                                  description: 'Latitude of the location, in decimal degrees'
                                  example: 49.6116
                                longitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: float
                                  description: 'Longitude of the location, in decimal degrees'
                                  example: 6.1319
                                geofence_radius_m:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Geofence radius around the location, in metres'
                                  example: 100
                                created_at:
                                  type:
                                    - string
                                    - 'null'
                                  format: date-time
                                  example: '2024-03-01T08:29:07Z'
                                  readOnly: true
                                updated_at:
                                  type:
                                    - string
                                    - 'null'
                                  format: date-time
                                  example: '2024-03-01T08:29:07Z'
                                  readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/sip-devices/{sip_device}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SipDevices
      summary: 'Get a sIP device'
      operationId: getSipDevice
      description: |
        Returns the sip device identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                  against the PBX. The device owner is exposed as a friendly `target_type`
                  (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                  The SIP password is never exposed.
                required:
                  - id
                  - pbx_id
                  - name
                  - is_enabled
                  - type
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'SIP device identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  target_type:
                    type:
                      - string
                      - 'null'
                    description: 'Friendly type of the entity the device is assigned to'
                    enum:
                      - user
                      - extension
                    example: user
                  target_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Identifier of the target entity'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  extension_id_shown_for_internal_calls:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: "Extension displayed in the device's caller ID for internal calls"
                    example: null
                  roaming_user_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'User currently roamed onto this device'
                    example: null
                  location_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Physical location the device is installed at'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  parent_sip_device_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                    example: null
                  name:
                    type: string
                    maxLength: 128
                    example: 'Reception desk phone'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    example: 'Front-desk Yealink T46U'
                  is_enabled:
                    type: boolean
                    description: 'Whether the device is currently enabled'
                    example: true
                  ip_internal:
                    type:
                      - string
                      - 'null'
                    description: 'Last-seen internal IP'
                    example: 192.168.1.42
                  ip_external:
                    type:
                      - string
                      - 'null'
                    description: 'Last-seen external IP'
                    example: 203.0.113.10
                  user_agent:
                    type:
                      - string
                      - 'null'
                    description: 'SIP User-Agent string reported by the device'
                    example: 'Yealink SIP-T46U 108.86.0.10'
                  mac:
                    type:
                      - string
                      - 'null'
                    description: 'MAC address'
                    example: '00:0a:95:9d:68:16'
                  vlan_phone:
                    type:
                      - integer
                      - 'null'
                    description: 'VLAN id for the phone interface'
                    example: 100
                  vlan_pc:
                    type:
                      - integer
                      - 'null'
                    description: 'VLAN id for the PC pass-through interface'
                    example: 200
                  sip_username:
                    type:
                      - string
                      - 'null'
                    maxLength: 24
                    description: 'SIP authentication username'
                    example: device_001
                  alt_username:
                    type:
                      - string
                      - 'null'
                    description: 'Alternate SIP username (used for multi-line registrations)'
                    example: null
                  transport:
                    type: string
                    description: 'SIP transport'
                    enum:
                      - udp
                      - tcp
                      - tls
                    example: tls
                  type:
                    type: string
                    description: 'Device provisioning category'
                    enum:
                      - auto
                      - manual
                      - gigaset
                      - trunk
                    example: auto
                  allow_roaming:
                    type: boolean
                    description: 'Whether the device accepts roamed-in users'
                    example: false
                  language:
                    type: string
                    description: 'Display language for the device'
                    example: en
                  easy_deploy:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp until which the device is in easy-deploy mode'
                    example: null
                  notify:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp at which a SIP NOTIFY was last requested'
                    example: null
                  allow_default_pbxes_outgoing_phone_numbers:
                    type: boolean
                    description: 'Whether the PBX default outbound numbers are usable from this device'
                    example: false
                  sync_source:
                    type: string
                    description: 'Provisioning origin'
                    enum:
                      - manual
                      - provision
                      - legacy_import
                    example: provision
                  custom_provisioning:
                    type:
                      - string
                      - 'null'
                    description: 'Custom provisioning template snippet'
                    example: null
                  last_seen:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last time the device registered'
                    example: '2024-03-01T08:29:07Z'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  target:
                    type: object
                    description: |
                      The resolved device owner (a user or an extension); shape varies by
                      `target_type`. Returned only when requested via `?include=target`.
                  tags:
                    type: array
                    description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                    items:
                      type: object
                      description: |
                        Free-form label that can be attached to users, SIP devices, phone numbers, and
                        other tenant resources for grouping, filtering, and reporting. Tags are scoped
                        to a single Pbx (tenant). Associations to the resources a tag is applied to are
                        held on the relevant pivot tables, not on this schema.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                          readOnly: true
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                          example: 'VIP Customers'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                          example: 'Customers with priority routing and dedicated agents.'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  caller_identities:
                    type: array
                    description: |
                      Caller identities available to this device. Returned only when requested
                      via `?include=callerIdentities`.
                    items:
                      type: object
                  location:
                    description: |
                      The resolved installation location. Returned only when requested via
                      `?include=location`.
                    allOf:
                      -
                        type: object
                        description: |
                          Physical office or site associated with a PBX. Locations form a nested-set
                          tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                          used for emergency call routing.
                        required:
                          - id
                          - pbx_id
                          - name
                        properties:
                          id:
                            type: string
                            format: uuid
                            description: 'Location identifier'
                            example: 550e8400-e29b-41d4-a716-446655440000
                            readOnly: true
                          pbx_id:
                            type: string
                            format: uuid
                            description: 'Pbx identifier (tenant)'
                            example: 550e8400-e29b-41d4-a716-446655440001
                          company_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Owning company identifier'
                            example: 550e8400-e29b-41d4-a716-446655440004
                          parent_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Parent location identifier in the nested-set tree'
                            example: 550e8400-e29b-41d4-a716-446655440002
                          name:
                            type: string
                            maxLength: 64
                            example: 'Luxembourg HQ'
                          description:
                            type:
                              - string
                              - 'null'
                            maxLength: 255
                            example: 'Main office, 5th floor'
                          street_no:
                            type:
                              - string
                              - 'null'
                            description: 'Street number portion of the address'
                            example: '12'
                          street:
                            type:
                              - string
                              - 'null'
                            example: 'Main Street'
                          city:
                            type:
                              - string
                              - 'null'
                            example: Luxembourg
                          postal:
                            type:
                              - string
                              - 'null'
                            description: 'Postal code'
                            example: '1234'
                          country_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Country identifier'
                            example: 550e8400-e29b-41d4-a716-446655440003
                          lft:
                            type:
                              - integer
                              - 'null'
                            description: 'Nested-set left bound'
                            example: 1
                          rgt:
                            type:
                              - integer
                              - 'null'
                            description: 'Nested-set right bound'
                            example: 10
                          depth:
                            type:
                              - integer
                              - 'null'
                            description: 'Tree depth (0 for root locations)'
                            example: 0
                          enable_location_as_presence_status:
                            type: boolean
                            description: 'Whether this location can be used as a presence status value'
                            example: false
                          style:
                            type:
                              - object
                              - 'null'
                            description: 'Optional presentation style (badge icon and colours) for the location'
                            example:
                              icon_class: la-map-pin
                              bg_color: '#3490dc'
                              font_color: '#ffffff'
                          is_fixed_location:
                            type: boolean
                            description: 'Whether this is a fixed (geofenced) physical location'
                            example: true
                          latitude:
                            type:
                              - number
                              - 'null'
                            format: float
                            description: 'Latitude of the location, in decimal degrees'
                            example: 49.6116
                          longitude:
                            type:
                              - number
                              - 'null'
                            format: float
                            description: 'Longitude of the location, in decimal degrees'
                            example: 6.1319
                          geofence_radius_m:
                            type:
                              - integer
                              - 'null'
                            description: 'Geofence radius around the location, in metres'
                            example: 100
                          created_at:
                            type:
                              - string
                              - 'null'
                            format: date-time
                            example: '2024-03-01T08:29:07Z'
                            readOnly: true
                          updated_at:
                            type:
                              - string
                              - 'null'
                            format: date-time
                            example: '2024-03-01T08:29:07Z'
                            readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /sip-devices/inventory:
    get:
      tags:
        - SipDevices
      summary: 'Get SIP device inventory'
      operationId: getSipDeviceInventory
      description: |
        Returns a paginated list of sip device inventory. Use the standard `search`, `sort`, `page`,
        and `perPage` query parameters; use `filter[key]=value` to narrow the result set.
        Multi-tenant scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                        pbx_id:
                          type: integer
                        mac_address:
                          type: string
                        model:
                          type:
                            - string
                            - 'null'
                        vendor:
                          type:
                            - string
                            - 'null'
                        status:
                          type: string
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 1
                    pbx_id: 1
                    mac_address: 'AA:BB:CC:DD:EE:FF'
                    model: 'Yealink T54W'
                    vendor: Yealink
                    status: provisioned
                    created_at: '2023-10-16T08:29:07.000000Z'
                    updated_at: '2023-10-16T08:29:07.000000Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /sound-files:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SoundFiles
      summary: 'List Sound file'
      operationId: listSoundFiles
      description: |
        Returns a paginated list of sound files. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `comment`, `type`, `source`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Audio asset used for greetings, prompts, music on hold, and voicemail.
                        Protected/built-in sound files have a `null` `pbx_id`. The raw audio payload
                        is never inlined; instead `audio_url` is a short-lived signed URL to a
                        streaming endpoint.
                      required:
                        - id
                        - name
                        - type
                        - source
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Sound file identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Pbx identifier (null for built-in/protected files)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        parent_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Identifier of the default/fallback announcement this record is a language
                            variant of. `null` for a top-level announcement. The list is flat and
                            includes variants: switch to a variant whose `language` matches the
                            caller's detected language, otherwise play the parent as the fallback.
                          example: 550e8400-e29b-41d4-a716-446655440002
                        name:
                          type: string
                          maxLength: 64
                          example: 'Welcome announcement'
                        comment:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Played at the start of the main IVR'
                        message:
                          type:
                            - string
                            - 'null'
                          description: 'TTS source text (only populated when `source = ai_generated`)'
                          example: 'Welcome to Customer Support. Press 1 for sales, 2 for support.'
                        ai_voice_id:
                          type:
                            - string
                            - 'null'
                          description: 'Identifier of the AI voice used to generate the audio'
                          example: voice_en_us_female_1
                        voice_settings:
                          type:
                            - object
                            - 'null'
                          description: 'AI voice tuning settings (pitch, speed, etc.) as a JSON object'
                          additionalProperties: true
                          example:
                            stability: 0.75
                            similarity_boost: 0.5
                        source:
                          type: string
                          description: 'Whether the audio was uploaded by the user or AI-generated'
                          enum:
                            - ai_generated
                            - uploaded_file
                          example: uploaded_file
                        type:
                          type: string
                          description: 'Intended use category for the sound'
                          enum:
                            - announcement
                            - music
                          example: announcement
                        language:
                          type:
                            - string
                            - 'null'
                          description: |
                            ISO-639-1 language of this announcement. Set on parents that have variants
                            and on every variant; may be `null` on a plain standalone announcement.
                            Used by the PBX to match a variant to the caller's detected language.
                          enum:
                            - en
                            - de
                            - fr
                            - lb
                            - es
                            - it
                            - pt
                            - nl
                            - pl
                            - ru
                            - tr
                            - sv
                            - da
                            - 'no'
                            - fi
                            - cs
                            - sk
                            - el
                            - hu
                            - ro
                            - bg
                            - hr
                            - uk
                            - ar
                            - he
                            - hi
                            - ja
                            - ko
                            - zh
                            - id
                            - ms
                            - th
                            - vi
                            - null
                          example: en
                        audio_url:
                          type: string
                          format: uri
                          description: |
                            Short-lived signed URL to a streaming endpoint for the audio. Plays
                            directly in an <audio src> with no auth header and expires after a short
                            window. The raw audio payload is never inlined in this response.
                          example: 'https://api.example.com/sound-files/550e8400-e29b-41d4-a716-446655440000/audio?signature=abc123&expires=1709280000'
                          readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/sound-files/{soundFile}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - SoundFiles
      summary: 'Get a sound File'
      operationId: getSoundFile
      description: |
        Returns the sound file identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Audio asset used for greetings, prompts, music on hold, and voicemail.
                  Protected/built-in sound files have a `null` `pbx_id`. The raw audio payload
                  is never inlined; instead `audio_url` is a short-lived signed URL to a
                  streaming endpoint.
                required:
                  - id
                  - name
                  - type
                  - source
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Sound file identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Pbx identifier (null for built-in/protected files)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  parent_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: |
                      Identifier of the default/fallback announcement this record is a language
                      variant of. `null` for a top-level announcement. The list is flat and
                      includes variants: switch to a variant whose `language` matches the
                      caller's detected language, otherwise play the parent as the fallback.
                    example: 550e8400-e29b-41d4-a716-446655440002
                  name:
                    type: string
                    maxLength: 64
                    example: 'Welcome announcement'
                  comment:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    example: 'Played at the start of the main IVR'
                  message:
                    type:
                      - string
                      - 'null'
                    description: 'TTS source text (only populated when `source = ai_generated`)'
                    example: 'Welcome to Customer Support. Press 1 for sales, 2 for support.'
                  ai_voice_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the AI voice used to generate the audio'
                    example: voice_en_us_female_1
                  voice_settings:
                    type:
                      - object
                      - 'null'
                    description: 'AI voice tuning settings (pitch, speed, etc.) as a JSON object'
                    additionalProperties: true
                    example:
                      stability: 0.75
                      similarity_boost: 0.5
                  source:
                    type: string
                    description: 'Whether the audio was uploaded by the user or AI-generated'
                    enum:
                      - ai_generated
                      - uploaded_file
                    example: uploaded_file
                  type:
                    type: string
                    description: 'Intended use category for the sound'
                    enum:
                      - announcement
                      - music
                    example: announcement
                  language:
                    type:
                      - string
                      - 'null'
                    description: |
                      ISO-639-1 language of this announcement. Set on parents that have variants
                      and on every variant; may be `null` on a plain standalone announcement.
                      Used by the PBX to match a variant to the caller's detected language.
                    enum:
                      - en
                      - de
                      - fr
                      - lb
                      - es
                      - it
                      - pt
                      - nl
                      - pl
                      - ru
                      - tr
                      - sv
                      - da
                      - 'no'
                      - fi
                      - cs
                      - sk
                      - el
                      - hu
                      - ro
                      - bg
                      - hr
                      - uk
                      - ar
                      - he
                      - hi
                      - ja
                      - ko
                      - zh
                      - id
                      - ms
                      - th
                      - vi
                      - null
                    example: en
                  audio_url:
                    type: string
                    format: uri
                    description: |
                      Short-lived signed URL to a streaming endpoint for the audio. Plays
                      directly in an <audio src> with no auth header and expires after a short
                      window. The raw audio payload is never inlined in this response.
                    example: 'https://api.example.com/sound-files/550e8400-e29b-41d4-a716-446655440000/audio?signature=abc123&expires=1709280000'
                    readOnly: true
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/sound-files/{soundFile}/audio':
    get:
      tags:
        - SoundFiles
      summary: "Stream a sound file's audio (user, pbx)"
      operationId: getSoundFileAudio
      description: |
        Stream the raw audio bytes of a sound file. The response is sent inline (not as
        an attachment) so it can be played directly, for example as the `src` of an
        HTML `<audio>` element. The `Content-Type` reflects the stored format
        (commonly `audio/mpeg`, but `audio/wav`, `audio/flac` or `audio/aac` may also
        be returned), falling back to `audio/mpeg`.

        This endpoint accepts EITHER of two authentication methods:

        - A temporary signed URL. This is the `audio_url` returned by the sound file
          resource (it embeds `expires` and `signature` query parameters and expires
          roughly one hour after it is minted). No `Authorization` header is required,
          which lets it be used directly in an `<audio src>`.
        - A bearer token carrying the `sound-files` ability. Used for durable or
          programmatic access; the stream is scoped to the token principal's PBX.

        When neither a valid signature nor a token is present the request is rejected
        with 401. A token that lacks the `sound-files` ability is rejected with 403.
      security:
        -
          bearerAuth: {}
        - {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: audio/mpeg
        -
          name: soundFile
          in: path
          required: true
          description: 'Sound file identifier.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: expires
          in: query
          required: false
          description: 'Expiry timestamp from the signed `audio_url`. Present only when authenticating with a signed URL.'
          schema:
            type: integer
            example: 1709280000
        -
          name: signature
          in: query
          required: false
          description: 'HMAC signature from the signed `audio_url`. Present only when authenticating with a signed URL.'
          schema:
            type: string
            example: abc123
      responses:
        200:
          description: 'Raw audio stream, sent inline.'
          headers:
            Content-Type:
              schema:
                type: string
                example: audio/mpeg
            Content-Disposition:
              schema:
                type: string
                example: 'inline; filename="Welcome announcement"'
          content:
            audio/mpeg:
              schema:
                type: string
                format: binary
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The bearer token does not carry the `sound-files` ability.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/sound-files/{soundFileId}/download':
    get:
      tags:
        - SoundFiles
      summary: 'Download a Sound File by ID'
      operationId: getSoundFileDownload
      security:
        -
          PbxServerAuth: {}
      description: |
        Returns the sound file download identified by the path parameter. Multi-tenant scoping is
        enforced: the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: audio/mpeg
        -
          name: soundFileId
          in: path
          schema:
            type: integer
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: 'localhost:8083'
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:16:41 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: audio/mpeg
            Content-Disposition:
              schema:
                type: string
                example: 'attachment; filename="soundFile-1.mp3"'
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 58
            Vary:
              schema:
                type: string
                example: Origin
          content:
            audio/mpeg:
              schema:
                type: string
                format: binary
                example: soundFile-1.mp3
              example: soundFile-1.mp3
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /layout:
    get:
      tags:
        - Users
      summary: 'Get the active Status Changer layout (user)'
      operationId: getUserLayout
      description: |
        Resolve and return the active Tempus Status Changer layout for the
        authenticated user. The PBX is derived server-side from the bearer token
        and cannot be supplied by the client.

        Resolution rules:

        - The user's PBX must be set on the token. If it is not, the request fails
          with `400`.
        - The active layout (`is_active = true`) for the user's PBX is selected. If
          the user belongs to a group and an active layout targets that group, the
          most recently created group-targeted layout wins; otherwise the first
          active layout for the PBX is returned.
        - If no active layout exists for the PBX, the request fails with `404`.

        The response is returned in the legacy `tempus` representation, wrapped in a
        `data` envelope, and includes a `filters` echo of any `filter` query values.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      options:
                        type: object
                        description: 'Client behaviour options for the layout.'
                        properties:
                          geoEnable:
                            type: boolean
                          geoForce:
                            type: boolean
                          postAction:
                            type: boolean
                          updateTimer:
                            type: integer
                            description: 'Status refresh interval in milliseconds.'
                      layout:
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                          mxvp_user_id:
                            type: string
                            format: uuid
                            description: 'The PBX identifier the layout belongs to.'
                          name:
                            type: string
                          displayflags:
                            type: string
                          type:
                            type: string
                          delete_date:
                            type:
                              - string
                              - 'null'
                          tl_layouts_statuses:
                            type: array
                            description: |
                              The statuses placed on the layout grid, in the legacy
                              Tempus shape.
                            items:
                              type: object
                              properties:
                                tllayout_id:
                                  type: string
                                  format: uuid
                                status_id:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                    mxvp_user_id:
                                      type: string
                                      format: uuid
                                    name:
                                      type: string
                                    icon:
                                      type:
                                        - string
                                        - 'null'
                                    fontcolor:
                                      type: string
                                    backgroundcolor:
                                      type: string
                                    css:
                                      type: string
                                    comment:
                                      type: string
                                    payable:
                                      type: boolean
                                    action:
                                      type:
                                        - string
                                        - 'null'
                                    migration_id:
                                      type:
                                        - string
                                        - 'null'
                                    mapping_id:
                                      type: integer
                                    delete_date:
                                      type:
                                        - string
                                        - 'null'
                                    sub_status_layouts:
                                      type: array
                                      items:
                                        type: object
                                    meta_data:
                                      type: object
                                    allow_multiselect:
                                      type: boolean
                                    sub_status_selection_mandatory:
                                      type: boolean
                                    sub_statuses:
                                      type: array
                                      items:
                                        type: object
                                        properties:
                                          id:
                                            type: string
                                            format: uuid
                                          name:
                                            type: string
                                          description:
                                            type:
                                              - string
                                              - 'null'
                                          style:
                                            type: object
                                position:
                                  type: integer
                                size:
                                  type: integer
                                toggle_status_id:
                                  type:
                                    - string
                                    - 'null'
                      preview_url:
                        type: string
                        format: uri
                        description: 'Absolute URL to a preview render of the layout.'
                  filters:
                    type: object
                    description: 'Echo of any `filter` query parameters supplied.'
              example:
                data:
                  options:
                    geoEnable: true
                    geoForce: false
                    postAction: false
                    updateTimer: 5000
                  layout:
                    id: 550e8400-e29b-41d4-a716-446655440000
                    mxvp_user_id: 550e8400-e29b-41d4-a716-446655440001
                    name: 'Customer Support'
                    displayflags: DWML
                    type: default
                    delete_date: null
                    tl_layouts_statuses:
                      -
                        tllayout_id: 550e8400-e29b-41d4-a716-446655440000
                        status_id:
                          id: 550e8400-e29b-41d4-a716-446655440010
                          mxvp_user_id: 550e8400-e29b-41d4-a716-446655440001
                          name: Working
                          icon: briefcase
                          fontcolor: '#FFFFFF'
                          backgroundcolor: '#1F8F4E'
                          css: ''
                          comment: ''
                          payable: false
                          action: null
                          migration_id: null
                          mapping_id: 0
                          delete_date: null
                          sub_status_layouts: {}
                          meta_data: {}
                          allow_multiselect: false
                          sub_status_selection_mandatory: false
                          sub_statuses:
                            -
                              id: 550e8400-e29b-41d4-a716-446655440020
                              name: 'Customer Support'
                              description: 'Handling inbound support calls'
                              style:
                                icon_class: headset
                        position: 0
                        size: 3
                        toggle_status_id: null
                  preview_url: 'https://cockpit.voxbi.com/layout-preview/550e8400-e29b-41d4-a716-446655440000'
                filters: {}
        400:
          description: |
            The authenticated user has no PBX associated with their token, so no
            layout can be resolved.
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /statuses:
    get:
      tags:
        - Statuses
      summary: 'List statuse'
      operationId: listStatuses
      description: |
        Returns a paginated list of statuses. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, pbx_id, mxvp_id, name, icon, font_color, background_color, css, comment, paid, action and sync_tempus.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Tempus presence status: a top-level value (for example Available, Lunch,
                        Meeting) that a user can broadcast. Visual styling is carried inside the
                        `style` JSON object and behavioural switches inside `meta_data.flags`.

                        This schema documents the default response shape returned by the status
                        endpoints. The API can also emit a legacy "tempus" representation (selected
                        by a format parameter) whose field names differ (`mxvp_user_id`, `icon`,
                        `fontcolor`, `backgroundcolor`, `comment`, and similar). Integrators should
                        target the default shape described here.

                        The `sub_statuses` array is only populated when the `subStatuses` relation is
                        eager loaded by the request; otherwise it is returned as an empty array.
                      required:
                        - id
                        - name
                        - description
                        - style
                        - availability
                        - meta_data
                        - allow_multiselect
                        - sub_status_selection_mandatory
                        - sub_statuses
                        - created_at
                        - updated_at
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique status identifier.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        name:
                          type: string
                          maxLength: 255
                          description: 'Human-readable name of the status as shown to users.'
                          example: Working
                        description:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-form description of what the status represents.'
                          example: 'Standard work activity'
                        style:
                          type:
                            - object
                            - 'null'
                          description: |
                            Visual styling for the status pill (icon and colours). Null when no
                            styling has been configured.
                          properties:
                            icon_class:
                              type:
                                - string
                                - 'null'
                              description: |
                                Font Awesome icon identifier rendered with the status (for example
                                briefcase, coffee, headset).
                              example: briefcase
                            font_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used for the foreground text of the status pill.'
                              example: '#FFFFFF'
                            bg_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used as the background of the status pill.'
                              example: '#1F8F4E'
                        availability:
                          type:
                            - string
                            - 'null'
                          description: |
                            Roll-up availability category exposed to telephony and presence features.
                            Null when the status has no mapped availability.
                          enum:
                            - available
                            - unavailable
                            - busy
                            - meeting
                            - away
                          example: available
                        meta_data:
                          type:
                            - object
                            - 'null'
                          description: |
                            Extended behavioural settings. The `flags` array carries opt-in switches
                            that drive status behaviour, such as `payable`, `pbx_reachable`,
                            `do_not_disturb`, `chat_available`, `temp_break`, `calculate_lunch_time`,
                            `pbx_not_reachable`, and `auto_stop_target`. Additional implementation
                            keys may also be present.
                          properties:
                            flags:
                              type: array
                              description: 'Behavioural flags currently enabled on this status.'
                              items:
                                type: string
                                enum:
                                  - calculate_lunch_time
                                  - pbx_reachable
                                  - payable
                                  - do_not_disturb
                                  - chat_available
                                  - temp_break
                                  - pbx_not_reachable
                                  - auto_stop_target
                              example:
                                - pbx_reachable
                                - payable
                        allow_multiselect:
                          type: boolean
                          description: |
                            Whether more than one sub-status can be selected at once while in this
                            status. Defaults to false.
                          example: false
                        sub_status_selection_mandatory:
                          type: boolean
                          description: |
                            Whether the user must pick a sub-status when entering this status.
                            Defaults to false.
                          example: false
                        sub_statuses:
                          type: array
                          description: |
                            Sub-statuses attached to this status. Only populated when the
                            `subStatuses` relation is eager loaded by the request; otherwise returned
                            as an empty array.
                          items:
                            type: object
                            required:
                              - id
                              - name
                              - description
                              - style
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique identifier of the sub-status.'
                                example: 550e8400-e29b-41d4-a716-446655440010
                              name:
                                type: string
                                description: 'Human-readable name of the sub-status.'
                                example: 'Customer Support'
                              description:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional free-form description of the sub-status.'
                                example: 'Handling inbound support calls'
                              style:
                                type:
                                  - object
                                  - 'null'
                                description: |
                                  Visual styling for the sub-status, mirroring the parent status
                                  `style` object (icon and colours). Null when not configured.
                                properties:
                                  icon_class:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Font Awesome icon identifier for the sub-status.'
                                    example: headset
                                  font_color:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Hex colour used for the foreground text.'
                                    example: '#FFFFFF'
                                  bg_color:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Hex colour used as the background.'
                                    example: '#2D6CDF'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the status was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the status was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    parent_id: 550e8400-e29b-41d4-a716-446655440000
                    name: Working
                    description: 'Standard work activity'
                    style:
                      icon_class: briefcase
                      font_color: '#FFFFFF'
                      bg_color: '#1F8F4E'
                    availability: available
                    meta_data:
                      flags:
                        - pbx_reachable
                        - payable
                    payable: true
                    allow_multiselect: false
                    sub_status_selection_mandatory: false
                    sub_statuses_enabled: true
                    ring_users_despite_right_to_disconnect: false
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/statuses/{id}':
    get:
      tags:
        - Statuses
      summary: 'Get a Statu'
      operationId: getStatus
      description: |
        Returns the status identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Tempus presence status: a top-level value (for example Available, Lunch,
                  Meeting) that a user can broadcast. Visual styling is carried inside the
                  `style` JSON object and behavioural switches inside `meta_data.flags`.

                  This schema documents the default response shape returned by the status
                  endpoints. The API can also emit a legacy "tempus" representation (selected
                  by a format parameter) whose field names differ (`mxvp_user_id`, `icon`,
                  `fontcolor`, `backgroundcolor`, `comment`, and similar). Integrators should
                  target the default shape described here.

                  The `sub_statuses` array is only populated when the `subStatuses` relation is
                  eager loaded by the request; otherwise it is returned as an empty array.
                required:
                  - id
                  - name
                  - description
                  - style
                  - availability
                  - meta_data
                  - allow_multiselect
                  - sub_status_selection_mandatory
                  - sub_statuses
                  - created_at
                  - updated_at
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique status identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  name:
                    type: string
                    maxLength: 255
                    description: 'Human-readable name of the status as shown to users.'
                    example: Working
                  description:
                    type:
                      - string
                      - 'null'
                    description: 'Optional free-form description of what the status represents.'
                    example: 'Standard work activity'
                  style:
                    type:
                      - object
                      - 'null'
                    description: |
                      Visual styling for the status pill (icon and colours). Null when no
                      styling has been configured.
                    properties:
                      icon_class:
                        type:
                          - string
                          - 'null'
                        description: |
                          Font Awesome icon identifier rendered with the status (for example
                          briefcase, coffee, headset).
                        example: briefcase
                      font_color:
                        type:
                          - string
                          - 'null'
                        description: 'Hex colour used for the foreground text of the status pill.'
                        example: '#FFFFFF'
                      bg_color:
                        type:
                          - string
                          - 'null'
                        description: 'Hex colour used as the background of the status pill.'
                        example: '#1F8F4E'
                  availability:
                    type:
                      - string
                      - 'null'
                    description: |
                      Roll-up availability category exposed to telephony and presence features.
                      Null when the status has no mapped availability.
                    enum:
                      - available
                      - unavailable
                      - busy
                      - meeting
                      - away
                    example: available
                  meta_data:
                    type:
                      - object
                      - 'null'
                    description: |
                      Extended behavioural settings. The `flags` array carries opt-in switches
                      that drive status behaviour, such as `payable`, `pbx_reachable`,
                      `do_not_disturb`, `chat_available`, `temp_break`, `calculate_lunch_time`,
                      `pbx_not_reachable`, and `auto_stop_target`. Additional implementation
                      keys may also be present.
                    properties:
                      flags:
                        type: array
                        description: 'Behavioural flags currently enabled on this status.'
                        items:
                          type: string
                          enum:
                            - calculate_lunch_time
                            - pbx_reachable
                            - payable
                            - do_not_disturb
                            - chat_available
                            - temp_break
                            - pbx_not_reachable
                            - auto_stop_target
                        example:
                          - pbx_reachable
                          - payable
                  allow_multiselect:
                    type: boolean
                    description: |
                      Whether more than one sub-status can be selected at once while in this
                      status. Defaults to false.
                    example: false
                  sub_status_selection_mandatory:
                    type: boolean
                    description: |
                      Whether the user must pick a sub-status when entering this status.
                      Defaults to false.
                    example: false
                  sub_statuses:
                    type: array
                    description: |
                      Sub-statuses attached to this status. Only populated when the
                      `subStatuses` relation is eager loaded by the request; otherwise returned
                      as an empty array.
                    items:
                      type: object
                      required:
                        - id
                        - name
                        - description
                        - style
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the sub-status.'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        name:
                          type: string
                          description: 'Human-readable name of the sub-status.'
                          example: 'Customer Support'
                        description:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-form description of the sub-status.'
                          example: 'Handling inbound support calls'
                        style:
                          type:
                            - object
                            - 'null'
                          description: |
                            Visual styling for the sub-status, mirroring the parent status
                            `style` object (icon and colours). Null when not configured.
                          properties:
                            icon_class:
                              type:
                                - string
                                - 'null'
                              description: 'Font Awesome icon identifier for the sub-status.'
                              example: headset
                            font_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used for the foreground text.'
                              example: '#FFFFFF'
                            bg_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used as the background.'
                              example: '#2D6CDF'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the status was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the status was last updated.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                parent_id: 550e8400-e29b-41d4-a716-446655440000
                name: Working
                description: 'Standard work activity'
                style:
                  icon_class: briefcase
                  font_color: '#FFFFFF'
                  bg_color: '#1F8F4E'
                availability: available
                meta_data:
                  flags:
                    - pbx_reachable
                    - payable
                payable: true
                allow_multiselect: false
                sub_status_selection_mandatory: false
                sub_statuses_enabled: true
                ring_users_despite_right_to_disconnect: false
                created_at: '2024-03-01T08:29:07Z'
                updated_at: '2024-03-01T08:29:07Z'
                deleted_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /sub-statuses:
    get:
      tags:
        - Substatuses
      summary: 'List substatuse'
      operationId: listSubStatuses
      description: |
        Returns a paginated list of sub statuses. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            The filter key can be any of the following keys: id, pbx_id, mxvp_user_id, name, icon, font_color, background_color, css, comment, action and sync_tempus.

            The filter value can be any string or number.

            You can also apply multiple filters using `filter[key1]=value1&filter[key2]=value2`.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Tempus sub-status: a refinement of a parent status (for example "Lunch" under
                        the "Away" status). Sub-statuses let a status be broken down into more specific
                        activity reasons. Visual styling (icon and colours) is held inside the `style`
                        JSON object.

                        The `usage` array is only present when the related parent statuses have been
                        eager-loaded (typically on a single-resource or detail response). When statuses
                        are not loaded it is returned as an empty array. Each `usage` entry describes a
                        parent `TempusStatus` that references this sub-status, together with the pivot
                        flags that govern how the sub-status behaves under that parent.
                      required:
                        - id
                        - name
                        - usage
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique sub-status identifier.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        name:
                          type: string
                          maxLength: 50
                          description: 'Display name of the sub-status shown to agents and in reports.'
                          example: Lunch
                        description:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-form description explaining the purpose of the sub-status.'
                          example: 'Midday lunch break'
                        style:
                          type:
                            - object
                            - 'null'
                          description: |
                            Visual styling for the sub-status. Drives the icon and colours used when
                            the sub-status is rendered as a pill or badge. Null when no styling is set.
                          properties:
                            icon_class:
                              type:
                                - string
                                - 'null'
                              description: |
                                Font Awesome icon identifier used for the sub-status. One of the
                                icon set allowed by the platform (for example "utensils", "coffee",
                                "headset", "car", "home").
                              example: utensils
                            font_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used for the foreground text or icon.'
                              example: '#FFFFFF'
                            bg_color:
                              type:
                                - string
                                - 'null'
                              description: 'Hex colour used as the sub-status pill background.'
                              example: '#E5A100'
                        usage:
                          type: array
                          description: |
                            Parent statuses that reference this sub-status, exposed only when the
                            `statuses` relationship is eager-loaded; otherwise returned as an empty
                            array. Each entry is a parent `TempusStatus` enriched with the pivot
                            configuration that controls how the sub-status behaves under that parent.
                          items:
                            type: object
                            required:
                              - id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique identifier of the parent status.'
                                example: 550e8400-e29b-41d4-a716-446655440010
                                readOnly: true
                              parent_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: |
                                  Identifier of the status this parent status is itself nested under,
                                  when statuses form a hierarchy. Null for a top-level status.
                                example: 550e8400-e29b-41d4-a716-446655440011
                              name:
                                type: string
                                description: 'Display name of the parent status.'
                                example: Away
                              description:
                                type:
                                  - string
                                  - 'null'
                                description: 'Optional free-form description of the parent status.'
                                example: 'Agent is away from the desk'
                              style:
                                type:
                                  - object
                                  - 'null'
                                description: |
                                  Visual styling for the parent status (icon and colours), mirroring
                                  the structure of the sub-status `style` object. Null when unset.
                                properties:
                                  icon_class:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Font Awesome icon identifier for the parent status.'
                                    example: pause
                                  font_color:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Hex colour used for the foreground text or icon.'
                                    example: '#FFFFFF'
                                  bg_color:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Hex colour used as the parent status pill background.'
                                    example: '#6C757D'
                              availability:
                                type:
                                  - string
                                  - 'null'
                                description: |
                                  Availability behaviour the parent status maps to (for example whether
                                  an agent in this status is considered available, away, or offline).
                                  Null when not configured.
                                example: away
                              meta_data:
                                type:
                                  - object
                                  - 'null'
                                description: |
                                  Extended settings for the parent status, such as feature flags.
                                  Returned as a free-form JSON object.
                                additionalProperties: true
                                example:
                                  flags:
                                    - billable
                              allow_multiselect:
                                type: boolean
                                description: |
                                  Whether multiple sub-statuses may be selected at once under this
                                  parent status. Defaults to false when not set on the pivot.
                                example: false
                              sub_status_selection_mandatory:
                                type: boolean
                                description: |
                                  Whether selecting a sub-status is mandatory when an agent enters this
                                  parent status. Defaults to false when not set on the pivot.
                                example: false
                              payable:
                                type: boolean
                                description: |
                                  Whether time recorded under this parent status counts as payable
                                  working time. Defaults to false when not set on the pivot.
                                example: true
                              mapping_id:
                                type:
                                  - string
                                  - 'null'
                                description: |
                                  Optional external mapping identifier used to align this status with a
                                  code in an integrated payroll or time-tracking system. Null when no
                                  mapping is configured.
                                example: PAYROLL-LUNCH-01
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the parent status was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the parent status was last updated.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the sub-status was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the sub-status was last updated.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    name: Lunch
                    description: 'Lunch break'
                    style:
                      icon_class: utensils
                      font_color: '#FFFFFF'
                      bg_color: '#E5A100'
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                    deleted_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'http://localhost/api/v1/resources?page=1'
                  last: 'http://localhost/api/v1/resources?page=1'
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'http://localhost/api/v1/resources?page=1'
                      label: first
                      active: true
                  path: 'http://localhost/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /tags:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Tags
      summary: 'List tag'
      operationId: listTags
      description: |
        Returns a paginated list of tags. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `name`, `description`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Free-form label that can be attached to users, SIP devices, phone numbers, and
                        other tenant resources for grouping, filtering, and reporting. Tags are scoped
                        to a single Pbx (tenant). Associations to the resources a tag is applied to are
                        held on the relevant pivot tables, not on this schema.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                          readOnly: true
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                          example: 'VIP Customers'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                          example: 'Customers with priority routing and dedicated agents.'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - Tags
      summary: 'Create a tag'
      operationId: createTag
      description: |
        Create a new tag and optionally attach it to a set of users and SIP devices.
        The `pbx_id` is forced from the authenticated user and must not be sent in
        the request body.
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pbx_id
                - name
              properties:
                pbx_id:
                  type: string
                  format: uuid
                  description: "Pbx identifier (tenant). Must match the authenticated user's PBX."
                name:
                  type: string
                  minLength: 3
                  maxLength: 64
                  description: 'Tag name (must be unique within the PBX)'
                description:
                  type:
                    - string
                    - 'null'
                  minLength: 3
                  maxLength: 255
                users:
                  type: array
                  description: 'Identifiers of users to attach this tag to'
                  items:
                    type: string
                    format: uuid
                sipDevices:
                  type: array
                  description: 'Identifiers of SIP devices to attach this tag to'
                  items:
                    type: string
                    format: uuid
            example:
              pbx_id: 550e8400-e29b-41d4-a716-446655440001
              name: VIP
              description: 'Customers with priority routing'
              users:
                - 550e8400-e29b-41d4-a716-446655440010
              sipDevices:
                - 550e8400-e29b-41d4-a716-446655440020
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Free-form label that can be attached to users, SIP devices, phone numbers, and
                      other tenant resources for grouping, filtering, and reporting. Tags are scoped
                      to a single Pbx (tenant). Associations to the resources a tag is applied to are
                      held on the relevant pivot tables, not on this schema.
                    required:
                      - id
                      - pbx_id
                      - name
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                        example: 550e8400-e29b-41d4-a716-446655440001
                        readOnly: true
                      name:
                        type: string
                        maxLength: 64
                        description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                        example: 'VIP Customers'
                      description:
                        type:
                          - string
                          - 'null'
                        maxLength: 255
                        description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                        example: 'Customers with priority routing and dedicated agents.'
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                        example: '2024-03-01T08:29:07Z'
                        readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/tags/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Tags
      summary: 'Get a Tag'
      operationId: getTag
      description: |
        Returns the tag identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Free-form label that can be attached to users, SIP devices, phone numbers, and
                  other tenant resources for grouping, filtering, and reporting. Tags are scoped
                  to a single Pbx (tenant). Associations to the resources a tag is applied to are
                  held on the relevant pivot tables, not on this schema.
                required:
                  - id
                  - pbx_id
                  - name
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                    readOnly: true
                  name:
                    type: string
                    maxLength: 64
                    description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                    example: 'VIP Customers'
                  description:
                    type:
                      - string
                      - 'null'
                    maxLength: 255
                    description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                    example: 'Customers with priority routing and dedicated agents.'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /twinnings:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Twinning
      summary: 'List twinning'
      operationId: listTwinnings
      description: |
        Returns a paginated list of twinnings. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `status`, `type`, `phone_number`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        Twinning: an external destination that rings alongside a user's extension
                        (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                        the twinned destination rings in parallel so the call can be answered away
                        from the desk phone. Tenant scoping is derived from the attached user; this
                        resource has no direct `pbx_id` column of its own.
                      required:
                        - id
                        - user_id
                        - status
                        - phone_number
                        - delay
                        - sync_source
                        - type
                        - dial_strategy
                        - fmc_enabled
                        - backup_phone_number
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the twinning.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        user_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        status:
                          type: string
                          enum:
                            - enabled
                            - disabled
                          description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                          example: enabled
                        phone_number:
                          type:
                            - string
                            - 'null'
                          description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                          example: '+12125550100'
                        delay:
                          type: integer
                          format: int32
                          minimum: 0
                          description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                          example: 5
                        sync_source:
                          type: string
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                          example: manual
                        type:
                          type: string
                          enum:
                            - mobile
                            - teams
                          description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                          example: mobile
                        dial_strategy:
                          type: string
                          enum:
                            - gsm_only
                            - voip_only
                            - voip_and_gsm_fallback
                          description: |
                            How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                            `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                            VoIP first and falls back to GSM. Only meaningful for mobile-type
                            twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                          example: voip_and_gsm_fallback
                        fmc_enabled:
                          type: boolean
                          description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                          example: false
                        backup_phone_number:
                          type:
                            - string
                            - 'null'
                          description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                          example: '+12125550101'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/twinnings/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Twinning
      summary: 'Get a Twinning'
      operationId: getTwinning
      description: |
        Returns the twinning identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  Twinning: an external destination that rings alongside a user's extension
                  (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                  the twinned destination rings in parallel so the call can be answered away
                  from the desk phone. Tenant scoping is derived from the attached user; this
                  resource has no direct `pbx_id` column of its own.
                required:
                  - id
                  - user_id
                  - status
                  - phone_number
                  - delay
                  - sync_source
                  - type
                  - dial_strategy
                  - fmc_enabled
                  - backup_phone_number
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique identifier of the twinning.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  user_id:
                    type: string
                    format: uuid
                    description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  status:
                    type: string
                    enum:
                      - enabled
                      - disabled
                    description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                    example: enabled
                  phone_number:
                    type:
                      - string
                      - 'null'
                    description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                    example: '+12125550100'
                  delay:
                    type: integer
                    format: int32
                    minimum: 0
                    description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                    example: 5
                  sync_source:
                    type: string
                    enum:
                      - manual
                      - provision
                      - legacy_import
                    description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                    example: manual
                  type:
                    type: string
                    enum:
                      - mobile
                      - teams
                    description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                    example: mobile
                  dial_strategy:
                    type: string
                    enum:
                      - gsm_only
                      - voip_only
                      - voip_and_gsm_fallback
                    description: |
                      How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                      `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                      VoIP first and falls back to GSM. Only meaningful for mobile-type
                      twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                    example: voip_and_gsm_fallback
                  fmc_enabled:
                    type: boolean
                    description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                    example: false
                  backup_phone_number:
                    type:
                      - string
                      - 'null'
                    description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                    example: '+12125550101'
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /users:
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Users
      summary: 'List user'
      operationId: listUsers
      description: |
        Returns a paginated list of users. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      x-codeSamples:
        -
          lang: curl
          label: cURL
          source: |
            curl 'https://cockpit.voxbi.com/api/v1/users?page=1&perPage=25' \
              -H 'Accept: application/json' \
              -H 'Authorization: Bearer <YOUR_TOKEN>'
        -
          lang: JavaScript
          label: 'JavaScript (fetch)'
          source: |
            const res = await fetch('https://cockpit.voxbi.com/api/v1/users?page=1&perPage=25', {
              headers: {
                'Accept': 'application/json',
                'Authorization': `Bearer ${token}`,
              },
            });
            const { data, meta, links } = await res.json();
        -
          lang: PHP
          label: 'PHP (Guzzle)'
          source: |
            $client = new GuzzleHttp\Client();
            $response = $client->get('https://cockpit.voxbi.com/api/v1/users', [
                'headers' => [
                    'Accept' => 'application/json',
                    'Authorization' => "Bearer {$token}",
                ],
                'query' => ['page' => 1, 'perPage' => 25, 'filter[status]' => 'active'],
            ]);
            $users = json_decode($response->getBody(), true)['data'];
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: search
          in: query
          required: false
          description: "Free-text search across the resource's searchable fields."
          schema:
            type: string
          example: whatever
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          required: false
          description: |
            Field to sort by. Prefix with `-` for descending order (e.g. `-created_at`).
          schema:
            type: string
          example: id
        -
          name: 'filter[key]'
          description: |
            Filter the list by one or more fields. Allowed keys: `first_name`, `last_name`, `email`, `status`, `vip`, `show_in_address_book`.
            Apply several at once with filter[key1]=value1&filter[key2]=value2.
          in: query
          required: false
          schema:
            type: string
          example: whateverValue
        -
          name: include
          description: |
            Comma-separated related resources to embed (dot-nested where
            shown). Allowed: `extensions`, `groups`, `allowManageGroupContacts`, `allowAccessToGroupContacts`, `sipDevices`, `twinnings`, `callerIdentities`, `locations`, `languages`, `tags`, `queues`.
          in: query
          required: false
          schema:
            type: string
          example: 'groups,callerIdentities'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        PBX user. Each user belongs to exactly one Pbx, owns optional extensions
                        and devices, and carries a large set of feature flags controlling what they
                        can do in the Voxbi UI and on the telephony stack.

                        Secrets and credentials are never exposed through the API. Relation keys are
                        opt-in via `?include=`.
                      required:
                        - id
                        - pbx_id
                        - first_name
                        - email
                        - status
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'User identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        first_name:
                          type: string
                          maxLength: 64
                          example: Jane
                        last_name:
                          type:
                            - string
                            - 'null'
                          maxLength: 64
                          example: Smith
                        name:
                          type: string
                          readOnly: true
                          description: 'Combined display name (accessor, respects PBX formatting settings)'
                          example: 'Jane Smith'
                        full_name_with_email:
                          type: string
                          readOnly: true
                          description: 'Convenience label combining the display name and email'
                          example: 'Jane Smith <jane.smith@example.com>'
                        email:
                          type: string
                          format: email
                          maxLength: 100
                          example: jane.smith@example.com
                        status:
                          type: string
                          enum:
                            - enabled
                            - disabled
                          example: enabled
                        type:
                          type: string
                          description: 'User category'
                          enum:
                            - user
                            - pickup_line
                          example: user
                        language:
                          type: string
                          description: 'Preferred UI language'
                          enum:
                            - en
                            - de
                            - fr
                          example: en
                        sync_source:
                          type: string
                          description: 'Provisioning origin'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                            - microsoft_entra
                          example: manual
                        vip:
                          type: boolean
                          description: 'Whether the user is flagged as VIP'
                          example: false
                        show_in_address_book:
                          type: boolean
                          description: 'Whether the user appears in the shared address book'
                          example: true
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Default outbound CID for this user'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        caller_identity_internal_extension_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension shown as the internal caller ID'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        caller_identity_external_extension_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension shown as the external caller ID'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        allow_telephony:
                          type: boolean
                          description: 'Whether the user can place and receive calls'
                          example: true
                        allow_call_forwarding:
                          type: boolean
                          example: true
                        allow_change_twinning_dest:
                          type: boolean
                          description: 'Whether the user may change their twinning destination'
                          example: true
                        allow_dnd:
                          type: boolean
                          description: 'Whether the user may set their own Do Not Disturb'
                          example: true
                        allow_status_changer:
                          type: boolean
                          description: "Whether the user may change other users' statuses"
                          example: false
                        allow_anonymous_calls:
                          type: boolean
                          description: 'Whether the user is allowed to place anonymous outbound calls'
                          example: false
                        allow_international_calls:
                          type: boolean
                          example: false
                        allow_eu_calls:
                          type: boolean
                          example: true
                        allow_national_calls:
                          type: boolean
                          example: true
                        allow_premium_numbers:
                          type: boolean
                          example: false
                        allow_sms:
                          type: boolean
                          example: false
                        allow_manage_global_contacts:
                          type: boolean
                          example: false
                        allow_manage_voicemail_parameters:
                          type: boolean
                          example: true
                        allow_in_call_recording:
                          type: boolean
                          description: 'Whether the user can start/stop recording during a call'
                          example: false
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: 'Whether the PBX default outbound numbers are usable by this user'
                          example: true
                        allow_grafana_access:
                          type: boolean
                          description: 'Whether the user can access the Grafana dashboards'
                          example: false
                        allow_right_to_disconnect:
                          type: boolean
                          description: 'Whether the user may set their own right-to-disconnect schedule'
                          example: true
                        right_to_disconnect:
                          type: boolean
                          description: 'Whether the right-to-disconnect rule is currently enforced'
                          example: false
                        concurrent_calls:
                          type: boolean
                          description: 'Whether the user may have multiple simultaneous calls'
                          example: true
                        extension_roaming:
                          type: boolean
                          description: 'Whether the user may hot-desk by logging into other devices'
                          example: true
                        record_your_calls:
                          type: boolean
                          description: 'Default per-call recording flag for outbound external calls'
                          example: false
                        record_your_internal_calls:
                          type: integer
                          description: |
                            Tri-state flag controlling internal-call recording (0 = off, 1 = on,
                            2 = follow PBX default). Stored as an integer despite the boolean-style
                            name.
                          example: 2
                        access_all_call_recordings:
                          type: boolean
                          description: 'Whether the user may access call recordings of others'
                          example: false
                        call_recordings_visibility:
                          type: string
                          enum:
                            - all_calls
                            - own_calls_only
                          example: own_calls_only
                        call_information_visibility:
                          type: string
                          enum:
                            - none
                            - own_calls
                            - own_group_only
                          example: own_calls
                        send_missed_call_via_email:
                          type: boolean
                          example: true
                        limit_email_missed_call_to_direct:
                          type: boolean
                          description: 'Whether missed-call emails are limited to directly-dialled calls'
                          example: false
                        show_caller_id_for_twinning_call:
                          type: integer
                          description: |
                            Tri-state flag controlling caller-ID display on twinning calls (0 = off,
                            1 = on, 2 = follow PBX default).
                          example: 2
                        voicemail_type:
                          type: string
                          description: 'Voicemail mode'
                          enum:
                            - disabled
                            - enabled
                            - internal
                            - external
                          example: internal
                        voicemail_destination:
                          type: string
                          description: 'Where voicemail notifications are sent'
                          enum:
                            - email_only
                            - email_and_phone
                          example: email_only
                        invited_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When the user was invited (if onboarding via invitation)'
                          example: null
                        accepted_invitation_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'When the user accepted their invitation'
                          example: null
                        email_verified_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-02-15T10:00:00Z'
                          readOnly: true
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        extensions:
                          type: array
                          description: 'Extensions owned by the user. Returned only when requested via `?include=extensions`.'
                          items:
                            type: object
                            description: |
                              Internal dial number assigned to a user, device, queue, or other PBX entity.
                              Per-direction call recording is controlled by the two `record_*_calls` flags.
                              The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                              (always present); the full `assigned_to` object is opt-in.
                            required:
                              - id
                              - pbx_id
                              - number
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Extension identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              assigned_to_type:
                                type:
                                  - string
                                  - 'null'
                                description: 'Friendly type of the entity this extension is assigned to'
                                enum:
                                  - user
                                  - sip_device
                                  - famulor_agent
                                example: user
                              assigned_to_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Identifier of the entity this extension is assigned to'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow applied to external inbound calls hitting this extension'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow applied to internal calls hitting this extension'
                                example: 550e8400-e29b-41d4-a716-446655440004
                              number:
                                type: string
                                maxLength: 16
                                description: 'Dialable extension digits'
                                example: '1337'
                              name:
                                type:
                                  - string
                                  - 'null'
                                description: 'Display name for the extension'
                                example: 'Support line'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Front-line support line'
                              record_external_calls:
                                type: boolean
                                description: 'Whether external calls on this extension are recorded'
                                example: true
                              record_internal_calls:
                                type: boolean
                                description: 'Whether internal calls on this extension are recorded'
                                example: false
                              sync_source:
                                type: string
                                description: 'Provisioning origin (cast to ExtensionSyncSource)'
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                example: manual
                              full_name_with_extension_number:
                                type:
                                  - string
                                  - 'null'
                                description: "Convenience label combining the assignee's name and the extension number"
                                example: 'Jane Smith (1337)'
                                readOnly: true
                              assigned_to:
                                type: object
                                description: |
                                  The resolved owner of this extension; shape varies by `assigned_to_type`.
                                  Returned only when requested via `?include=user` (or `?include=sipDevice`
                                  / `?include=famulorAgent`).
                              employee_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: |
                                  Identifier of the employee record linked to the assigned user.
                                  Returned only when requested via `?include=user.employee`.
                                example: 550e8400-e29b-41d4-a716-446655440005
                              department_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: |
                                  Department of the assigned user's employee, taken from their currently
                                  active contract (null when the employee has no active contract).
                                  Returned only when requested via `?include=user.employee`.
                                example: 550e8400-e29b-41d4-a716-446655440006
                              is_favorite:
                                type: boolean
                                description: |
                                  Whether the extension's user is one of the **calling user's** favourites.
                                  PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                                  OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        groups:
                          type: array
                          description: 'Groups the user belongs to. Returned only when requested via `?include=groups`.'
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        allow_manage_group_contacts:
                          type: array
                          description: |
                            Groups whose contacts the user may manage. Returned only when requested
                            via `?include=allowManageGroupContacts`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        allow_access_to_group_contacts:
                          type: array
                          description: |
                            Groups whose contacts the user may access. Returned only when requested
                            via `?include=allowAccessToGroupContacts`.
                          items:
                            type: object
                            description: |
                              Group of users that share routing defaults and (optionally) a common caller
                              identity. Many fields are foreign keys pointing at defaults used when the
                              group's users place or receive calls.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Group identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              default_internal_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for internal calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              default_external_call_flow_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Call flow used for external calls reaching this group'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_outside_the_group:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Extension displayed to non-group members'
                                example: 550e8400-e29b-41d4-a716-446655440005
                              default_caller_identity_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Default caller identity applied to the group's outbound calls"
                                example: 550e8400-e29b-41d4-a716-446655440004
                              external_uid:
                                type:
                                  - string
                                  - 'null'
                                description: 'External identifier from a CRM or directory sync'
                                example: grp-support
                              allow_call_pickups:
                                type: boolean
                                description: "Whether group members may pick up each others' ringing calls"
                                example: true
                              name:
                                type: string
                                maxLength: 64
                                example: 'Support team'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'First-line support'
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: "Whether the group's CIDs include the PBX-default outbound numbers"
                                example: false
                              display_tab_to_everyone_inside_voxbi:
                                type: boolean
                                description: "Whether the group's tab is shown to everyone in the PBX"
                                example: false
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              users:
                                type: array
                                description: |
                                  Members of the group, each as a user reference. Returned only when
                                  requested via `?include=users`.
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      example: 550e8400-e29b-41d4-a716-446655440006
                                      readOnly: true
                                    first_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Jane
                                    last_name:
                                      type:
                                        - string
                                        - 'null'
                                      example: Smith
                                    email:
                                      type:
                                        - string
                                        - 'null'
                                      format: email
                                      example: jane.smith@example.com
                        sip_devices:
                          type: array
                          description: 'SIP devices assigned to the user. Returned only when requested via `?include=sipDevices`.'
                          items:
                            type: object
                            description: |
                              Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                              against the PBX. The device owner is exposed as a friendly `target_type`
                              (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                              The SIP password is never exposed.
                            required:
                              - id
                              - pbx_id
                              - name
                              - is_enabled
                              - type
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'SIP device identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              target_type:
                                type:
                                  - string
                                  - 'null'
                                description: 'Friendly type of the entity the device is assigned to'
                                enum:
                                  - user
                                  - extension
                                example: user
                              target_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Identifier of the target entity'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              extension_id_shown_for_internal_calls:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: "Extension displayed in the device's caller ID for internal calls"
                                example: null
                              roaming_user_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'User currently roamed onto this device'
                                example: null
                              location_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Physical location the device is installed at'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              parent_sip_device_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                                example: null
                              name:
                                type: string
                                maxLength: 128
                                example: 'Reception desk phone'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Front-desk Yealink T46U'
                              is_enabled:
                                type: boolean
                                description: 'Whether the device is currently enabled'
                                example: true
                              ip_internal:
                                type:
                                  - string
                                  - 'null'
                                description: 'Last-seen internal IP'
                                example: 192.168.1.42
                              ip_external:
                                type:
                                  - string
                                  - 'null'
                                description: 'Last-seen external IP'
                                example: 203.0.113.10
                              user_agent:
                                type:
                                  - string
                                  - 'null'
                                description: 'SIP User-Agent string reported by the device'
                                example: 'Yealink SIP-T46U 108.86.0.10'
                              mac:
                                type:
                                  - string
                                  - 'null'
                                description: 'MAC address'
                                example: '00:0a:95:9d:68:16'
                              vlan_phone:
                                type:
                                  - integer
                                  - 'null'
                                description: 'VLAN id for the phone interface'
                                example: 100
                              vlan_pc:
                                type:
                                  - integer
                                  - 'null'
                                description: 'VLAN id for the PC pass-through interface'
                                example: 200
                              sip_username:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 24
                                description: 'SIP authentication username'
                                example: device_001
                              alt_username:
                                type:
                                  - string
                                  - 'null'
                                description: 'Alternate SIP username (used for multi-line registrations)'
                                example: null
                              transport:
                                type: string
                                description: 'SIP transport'
                                enum:
                                  - udp
                                  - tcp
                                  - tls
                                example: tls
                              type:
                                type: string
                                description: 'Device provisioning category'
                                enum:
                                  - auto
                                  - manual
                                  - gigaset
                                  - trunk
                                example: auto
                              allow_roaming:
                                type: boolean
                                description: 'Whether the device accepts roamed-in users'
                                example: false
                              language:
                                type: string
                                description: 'Display language for the device'
                                example: en
                              easy_deploy:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp until which the device is in easy-deploy mode'
                                example: null
                              notify:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp at which a SIP NOTIFY was last requested'
                                example: null
                              allow_default_pbxes_outgoing_phone_numbers:
                                type: boolean
                                description: 'Whether the PBX default outbound numbers are usable from this device'
                                example: false
                              sync_source:
                                type: string
                                description: 'Provisioning origin'
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                example: provision
                              custom_provisioning:
                                type:
                                  - string
                                  - 'null'
                                description: 'Custom provisioning template snippet'
                                example: null
                              last_seen:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Last time the device registered'
                                example: '2024-03-01T08:29:07Z'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              target:
                                type: object
                                description: |
                                  The resolved device owner (a user or an extension); shape varies by
                                  `target_type`. Returned only when requested via `?include=target`.
                              tags:
                                type: array
                                description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                                items:
                                  type: object
                                  description: |
                                    Free-form label that can be attached to users, SIP devices, phone numbers, and
                                    other tenant resources for grouping, filtering, and reporting. Tags are scoped
                                    to a single Pbx (tenant). Associations to the resources a tag is applied to are
                                    held on the relevant pivot tables, not on this schema.
                                  required:
                                    - id
                                    - pbx_id
                                    - name
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                      description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                      example: 550e8400-e29b-41d4-a716-446655440000
                                      readOnly: true
                                    pbx_id:
                                      type: string
                                      format: uuid
                                      description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                      example: 550e8400-e29b-41d4-a716-446655440001
                                      readOnly: true
                                    name:
                                      type: string
                                      maxLength: 64
                                      description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                      example: 'VIP Customers'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                      maxLength: 255
                                      description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                      example: 'Customers with priority routing and dedicated agents.'
                                    created_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                                    updated_at:
                                      type:
                                        - string
                                        - 'null'
                                      format: date-time
                                      description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                      example: '2024-03-01T08:29:07Z'
                                      readOnly: true
                              caller_identities:
                                type: array
                                description: |
                                  Caller identities available to this device. Returned only when requested
                                  via `?include=callerIdentities`.
                                items:
                                  type: object
                              location:
                                description: |
                                  The resolved installation location. Returned only when requested via
                                  `?include=location`.
                                allOf:
                                  -
                                    type: object
                                    description: |
                                      Physical office or site associated with a PBX. Locations form a nested-set
                                      tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                      used for emergency call routing.
                                    required:
                                      - id
                                      - pbx_id
                                      - name
                                    properties:
                                      id:
                                        type: string
                                        format: uuid
                                        description: 'Location identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440000
                                        readOnly: true
                                      pbx_id:
                                        type: string
                                        format: uuid
                                        description: 'Pbx identifier (tenant)'
                                        example: 550e8400-e29b-41d4-a716-446655440001
                                      company_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Owning company identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440004
                                      parent_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Parent location identifier in the nested-set tree'
                                        example: 550e8400-e29b-41d4-a716-446655440002
                                      name:
                                        type: string
                                        maxLength: 64
                                        example: 'Luxembourg HQ'
                                      description:
                                        type:
                                          - string
                                          - 'null'
                                        maxLength: 255
                                        example: 'Main office, 5th floor'
                                      street_no:
                                        type:
                                          - string
                                          - 'null'
                                        description: 'Street number portion of the address'
                                        example: '12'
                                      street:
                                        type:
                                          - string
                                          - 'null'
                                        example: 'Main Street'
                                      city:
                                        type:
                                          - string
                                          - 'null'
                                        example: Luxembourg
                                      postal:
                                        type:
                                          - string
                                          - 'null'
                                        description: 'Postal code'
                                        example: '1234'
                                      country_id:
                                        type:
                                          - string
                                          - 'null'
                                        format: uuid
                                        description: 'Country identifier'
                                        example: 550e8400-e29b-41d4-a716-446655440003
                                      lft:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Nested-set left bound'
                                        example: 1
                                      rgt:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Nested-set right bound'
                                        example: 10
                                      depth:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Tree depth (0 for root locations)'
                                        example: 0
                                      enable_location_as_presence_status:
                                        type: boolean
                                        description: 'Whether this location can be used as a presence status value'
                                        example: false
                                      style:
                                        type:
                                          - object
                                          - 'null'
                                        description: 'Optional presentation style (badge icon and colours) for the location'
                                        example:
                                          icon_class: la-map-pin
                                          bg_color: '#3490dc'
                                          font_color: '#ffffff'
                                      is_fixed_location:
                                        type: boolean
                                        description: 'Whether this is a fixed (geofenced) physical location'
                                        example: true
                                      latitude:
                                        type:
                                          - number
                                          - 'null'
                                        format: float
                                        description: 'Latitude of the location, in decimal degrees'
                                        example: 49.6116
                                      longitude:
                                        type:
                                          - number
                                          - 'null'
                                        format: float
                                        description: 'Longitude of the location, in decimal degrees'
                                        example: 6.1319
                                      geofence_radius_m:
                                        type:
                                          - integer
                                          - 'null'
                                        description: 'Geofence radius around the location, in metres'
                                        example: 100
                                      created_at:
                                        type:
                                          - string
                                          - 'null'
                                        format: date-time
                                        example: '2024-03-01T08:29:07Z'
                                        readOnly: true
                                      updated_at:
                                        type:
                                          - string
                                          - 'null'
                                        format: date-time
                                        example: '2024-03-01T08:29:07Z'
                                        readOnly: true
                        twinnings:
                          type: array
                          description: 'Twinnings configured for the user. Returned only when requested via `?include=twinnings`.'
                          items:
                            type: object
                            description: |
                              Twinning: an external destination that rings alongside a user's extension
                              (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                              the twinned destination rings in parallel so the call can be answered away
                              from the desk phone. Tenant scoping is derived from the attached user; this
                              resource has no direct `pbx_id` column of its own.
                            required:
                              - id
                              - user_id
                              - status
                              - phone_number
                              - delay
                              - sync_source
                              - type
                              - dial_strategy
                              - fmc_enabled
                              - backup_phone_number
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique identifier of the twinning.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              user_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              status:
                                type: string
                                enum:
                                  - enabled
                                  - disabled
                                description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                                example: enabled
                              phone_number:
                                type:
                                  - string
                                  - 'null'
                                description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                                example: '+12125550100'
                              delay:
                                type: integer
                                format: int32
                                minimum: 0
                                description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                                example: 5
                              sync_source:
                                type: string
                                enum:
                                  - manual
                                  - provision
                                  - legacy_import
                                description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                                example: manual
                              type:
                                type: string
                                enum:
                                  - mobile
                                  - teams
                                description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                                example: mobile
                              dial_strategy:
                                type: string
                                enum:
                                  - gsm_only
                                  - voip_only
                                  - voip_and_gsm_fallback
                                description: |
                                  How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                                  `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                                  VoIP first and falls back to GSM. Only meaningful for mobile-type
                                  twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                                example: voip_and_gsm_fallback
                              fmc_enabled:
                                type: boolean
                                description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                                example: false
                              backup_phone_number:
                                type:
                                  - string
                                  - 'null'
                                description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                                example: '+12125550101'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        caller_identities:
                          type: array
                          description: |
                            Effective (inherited) caller identities for the user: own plus those of
                            the user's groups plus the PBX's. Returned only when requested via
                            `?include=callerIdentities`.
                          items:
                            type: object
                        locations:
                          type: array
                          description: 'Locations the user is associated with. Returned only when requested via `?include=locations`.'
                          items:
                            type: object
                            description: |
                              Physical office or site associated with a PBX. Locations form a nested-set
                              tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                              used for emergency call routing.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Location identifier'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Pbx identifier (tenant)'
                                example: 550e8400-e29b-41d4-a716-446655440001
                              company_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Owning company identifier'
                                example: 550e8400-e29b-41d4-a716-446655440004
                              parent_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Parent location identifier in the nested-set tree'
                                example: 550e8400-e29b-41d4-a716-446655440002
                              name:
                                type: string
                                maxLength: 64
                                example: 'Luxembourg HQ'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                example: 'Main office, 5th floor'
                              street_no:
                                type:
                                  - string
                                  - 'null'
                                description: 'Street number portion of the address'
                                example: '12'
                              street:
                                type:
                                  - string
                                  - 'null'
                                example: 'Main Street'
                              city:
                                type:
                                  - string
                                  - 'null'
                                example: Luxembourg
                              postal:
                                type:
                                  - string
                                  - 'null'
                                description: 'Postal code'
                                example: '1234'
                              country_id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                                description: 'Country identifier'
                                example: 550e8400-e29b-41d4-a716-446655440003
                              lft:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Nested-set left bound'
                                example: 1
                              rgt:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Nested-set right bound'
                                example: 10
                              depth:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Tree depth (0 for root locations)'
                                example: 0
                              enable_location_as_presence_status:
                                type: boolean
                                description: 'Whether this location can be used as a presence status value'
                                example: false
                              style:
                                type:
                                  - object
                                  - 'null'
                                description: 'Optional presentation style (badge icon and colours) for the location'
                                example:
                                  icon_class: la-map-pin
                                  bg_color: '#3490dc'
                                  font_color: '#ffffff'
                              is_fixed_location:
                                type: boolean
                                description: 'Whether this is a fixed (geofenced) physical location'
                                example: true
                              latitude:
                                type:
                                  - number
                                  - 'null'
                                format: float
                                description: 'Latitude of the location, in decimal degrees'
                                example: 49.6116
                              longitude:
                                type:
                                  - number
                                  - 'null'
                                format: float
                                description: 'Longitude of the location, in decimal degrees'
                                example: 6.1319
                              geofence_radius_m:
                                type:
                                  - integer
                                  - 'null'
                                description: 'Geofence radius around the location, in metres'
                                example: 100
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        languages:
                          type: array
                          description: 'Languages the user is associated with. Returned only when requested via `?include=languages`.'
                          items:
                            type: object
                            description: |
                              A language defined for the tenant, used to label sound files, voice prompts
                              (IVR announcements), and per-user language preferences. Each language belongs
                              to exactly one Pbx (tenant) and is identified by a free-text name.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique language identifier (UUID).'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this language.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable language name as shown in the cockpit and selectors.'
                                example: English
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        tags:
                          type: array
                          description: 'Tags attached to the user. Returned only when requested via `?include=tags`.'
                          items:
                            type: object
                            description: |
                              Free-form label that can be attached to users, SIP devices, phone numbers, and
                              other tenant resources for grouping, filtering, and reporting. Tags are scoped
                              to a single Pbx (tenant). Associations to the resources a tag is applied to are
                              held on the relevant pivot tables, not on this schema.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                example: 'VIP Customers'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                example: 'Customers with priority routing and dedicated agents.'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        queues:
                          type: array
                          description: 'Queues the user is a member of. Returned only when requested via `?include=queues`.'
                          items:
                            type: object
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{id}':
    get:
      security:
        -
          bearerAuth: {}
        -
          IntegrationApiKey: {}
      tags:
        - Users
      summary: 'Get an User'
      operationId: getUser
      description: |
        Returns the user identified by the path parameter. Multi-tenant scoping is enforced: the
        caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: |
                  PBX user. Each user belongs to exactly one Pbx, owns optional extensions
                  and devices, and carries a large set of feature flags controlling what they
                  can do in the Voxbi UI and on the telephony stack.

                  Secrets and credentials are never exposed through the API. Relation keys are
                  opt-in via `?include=`.
                required:
                  - id
                  - pbx_id
                  - first_name
                  - email
                  - status
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'User identifier'
                    example: 550e8400-e29b-41d4-a716-446655440000
                    readOnly: true
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'Pbx identifier (tenant)'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  first_name:
                    type: string
                    maxLength: 64
                    example: Jane
                  last_name:
                    type:
                      - string
                      - 'null'
                    maxLength: 64
                    example: Smith
                  name:
                    type: string
                    readOnly: true
                    description: 'Combined display name (accessor, respects PBX formatting settings)'
                    example: 'Jane Smith'
                  full_name_with_email:
                    type: string
                    readOnly: true
                    description: 'Convenience label combining the display name and email'
                    example: 'Jane Smith <jane.smith@example.com>'
                  email:
                    type: string
                    format: email
                    maxLength: 100
                    example: jane.smith@example.com
                  status:
                    type: string
                    enum:
                      - enabled
                      - disabled
                    example: enabled
                  type:
                    type: string
                    description: 'User category'
                    enum:
                      - user
                      - pickup_line
                    example: user
                  language:
                    type: string
                    description: 'Preferred UI language'
                    enum:
                      - en
                      - de
                      - fr
                    example: en
                  sync_source:
                    type: string
                    description: 'Provisioning origin'
                    enum:
                      - manual
                      - provision
                      - legacy_import
                      - microsoft_entra
                    example: manual
                  vip:
                    type: boolean
                    description: 'Whether the user is flagged as VIP'
                    example: false
                  show_in_address_book:
                    type: boolean
                    description: 'Whether the user appears in the shared address book'
                    example: true
                  default_caller_identity_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Default outbound CID for this user'
                    example: 550e8400-e29b-41d4-a716-446655440004
                  caller_identity_internal_extension_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Extension shown as the internal caller ID'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  caller_identity_external_extension_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Extension shown as the external caller ID'
                    example: 550e8400-e29b-41d4-a716-446655440003
                  allow_telephony:
                    type: boolean
                    description: 'Whether the user can place and receive calls'
                    example: true
                  allow_call_forwarding:
                    type: boolean
                    example: true
                  allow_change_twinning_dest:
                    type: boolean
                    description: 'Whether the user may change their twinning destination'
                    example: true
                  allow_dnd:
                    type: boolean
                    description: 'Whether the user may set their own Do Not Disturb'
                    example: true
                  allow_status_changer:
                    type: boolean
                    description: "Whether the user may change other users' statuses"
                    example: false
                  allow_anonymous_calls:
                    type: boolean
                    description: 'Whether the user is allowed to place anonymous outbound calls'
                    example: false
                  allow_international_calls:
                    type: boolean
                    example: false
                  allow_eu_calls:
                    type: boolean
                    example: true
                  allow_national_calls:
                    type: boolean
                    example: true
                  allow_premium_numbers:
                    type: boolean
                    example: false
                  allow_sms:
                    type: boolean
                    example: false
                  allow_manage_global_contacts:
                    type: boolean
                    example: false
                  allow_manage_voicemail_parameters:
                    type: boolean
                    example: true
                  allow_in_call_recording:
                    type: boolean
                    description: 'Whether the user can start/stop recording during a call'
                    example: false
                  allow_default_pbxes_outgoing_phone_numbers:
                    type: boolean
                    description: 'Whether the PBX default outbound numbers are usable by this user'
                    example: true
                  allow_grafana_access:
                    type: boolean
                    description: 'Whether the user can access the Grafana dashboards'
                    example: false
                  allow_right_to_disconnect:
                    type: boolean
                    description: 'Whether the user may set their own right-to-disconnect schedule'
                    example: true
                  right_to_disconnect:
                    type: boolean
                    description: 'Whether the right-to-disconnect rule is currently enforced'
                    example: false
                  concurrent_calls:
                    type: boolean
                    description: 'Whether the user may have multiple simultaneous calls'
                    example: true
                  extension_roaming:
                    type: boolean
                    description: 'Whether the user may hot-desk by logging into other devices'
                    example: true
                  record_your_calls:
                    type: boolean
                    description: 'Default per-call recording flag for outbound external calls'
                    example: false
                  record_your_internal_calls:
                    type: integer
                    description: |
                      Tri-state flag controlling internal-call recording (0 = off, 1 = on,
                      2 = follow PBX default). Stored as an integer despite the boolean-style
                      name.
                    example: 2
                  access_all_call_recordings:
                    type: boolean
                    description: 'Whether the user may access call recordings of others'
                    example: false
                  call_recordings_visibility:
                    type: string
                    enum:
                      - all_calls
                      - own_calls_only
                    example: own_calls_only
                  call_information_visibility:
                    type: string
                    enum:
                      - none
                      - own_calls
                      - own_group_only
                    example: own_calls
                  send_missed_call_via_email:
                    type: boolean
                    example: true
                  limit_email_missed_call_to_direct:
                    type: boolean
                    description: 'Whether missed-call emails are limited to directly-dialled calls'
                    example: false
                  show_caller_id_for_twinning_call:
                    type: integer
                    description: |
                      Tri-state flag controlling caller-ID display on twinning calls (0 = off,
                      1 = on, 2 = follow PBX default).
                    example: 2
                  voicemail_type:
                    type: string
                    description: 'Voicemail mode'
                    enum:
                      - disabled
                      - enabled
                      - internal
                      - external
                    example: internal
                  voicemail_destination:
                    type: string
                    description: 'Where voicemail notifications are sent'
                    enum:
                      - email_only
                      - email_and_phone
                    example: email_only
                  invited_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When the user was invited (if onboarding via invitation)'
                    example: null
                  accepted_invitation_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'When the user accepted their invitation'
                    example: null
                  email_verified_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-02-15T10:00:00Z'
                    readOnly: true
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2024-03-01T08:29:07Z'
                    readOnly: true
                  extensions:
                    type: array
                    description: 'Extensions owned by the user. Returned only when requested via `?include=extensions`.'
                    items:
                      type: object
                      description: |
                        Internal dial number assigned to a user, device, queue, or other PBX entity.
                        Per-direction call recording is controlled by the two `record_*_calls` flags.
                        The assignment is exposed as a friendly `assigned_to_type` + `assigned_to_id`
                        (always present); the full `assigned_to` object is opt-in.
                      required:
                        - id
                        - pbx_id
                        - number
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Extension identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        assigned_to_type:
                          type:
                            - string
                            - 'null'
                          description: 'Friendly type of the entity this extension is assigned to'
                          enum:
                            - user
                            - sip_device
                            - famulor_agent
                          example: user
                        assigned_to_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the entity this extension is assigned to'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to external inbound calls hitting this extension'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow applied to internal calls hitting this extension'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        number:
                          type: string
                          maxLength: 16
                          description: 'Dialable extension digits'
                          example: '1337'
                        name:
                          type:
                            - string
                            - 'null'
                          description: 'Display name for the extension'
                          example: 'Support line'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Front-line support line'
                        record_external_calls:
                          type: boolean
                          description: 'Whether external calls on this extension are recorded'
                          example: true
                        record_internal_calls:
                          type: boolean
                          description: 'Whether internal calls on this extension are recorded'
                          example: false
                        sync_source:
                          type: string
                          description: 'Provisioning origin (cast to ExtensionSyncSource)'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          example: manual
                        full_name_with_extension_number:
                          type:
                            - string
                            - 'null'
                          description: "Convenience label combining the assignee's name and the extension number"
                          example: 'Jane Smith (1337)'
                          readOnly: true
                        assigned_to:
                          type: object
                          description: |
                            The resolved owner of this extension; shape varies by `assigned_to_type`.
                            Returned only when requested via `?include=user` (or `?include=sipDevice`
                            / `?include=famulorAgent`).
                        employee_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Identifier of the employee record linked to the assigned user.
                            Returned only when requested via `?include=user.employee`.
                          example: 550e8400-e29b-41d4-a716-446655440005
                        department_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: |
                            Department of the assigned user's employee, taken from their currently
                            active contract (null when the employee has no active contract).
                            Returned only when requested via `?include=user.employee`.
                          example: 550e8400-e29b-41d4-a716-446655440006
                        is_favorite:
                          type: boolean
                          description: |
                            Whether the extension's user is one of the **calling user's** favourites.
                            PRINCIPAL-CONDITIONAL: returned only for user-owned (Bearer) tokens and
                            OMITTED entirely for PBX API-key tokens (a PBX has no per-user favourites).
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  groups:
                    type: array
                    description: 'Groups the user belongs to. Returned only when requested via `?include=groups`.'
                    items:
                      type: object
                      description: |
                        Group of users that share routing defaults and (optionally) a common caller
                        identity. Many fields are foreign keys pointing at defaults used when the
                        group's users place or receive calls.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Group identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for internal calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for external calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_outside_the_group:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension displayed to non-group members'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Default caller identity applied to the group's outbound calls"
                          example: 550e8400-e29b-41d4-a716-446655440004
                        external_uid:
                          type:
                            - string
                            - 'null'
                          description: 'External identifier from a CRM or directory sync'
                          example: grp-support
                        allow_call_pickups:
                          type: boolean
                          description: "Whether group members may pick up each others' ringing calls"
                          example: true
                        name:
                          type: string
                          maxLength: 64
                          example: 'Support team'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'First-line support'
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: "Whether the group's CIDs include the PBX-default outbound numbers"
                          example: false
                        display_tab_to_everyone_inside_voxbi:
                          type: boolean
                          description: "Whether the group's tab is shown to everyone in the PBX"
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        users:
                          type: array
                          description: |
                            Members of the group, each as a user reference. Returned only when
                            requested via `?include=users`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                  allow_manage_group_contacts:
                    type: array
                    description: |
                      Groups whose contacts the user may manage. Returned only when requested
                      via `?include=allowManageGroupContacts`.
                    items:
                      type: object
                      description: |
                        Group of users that share routing defaults and (optionally) a common caller
                        identity. Many fields are foreign keys pointing at defaults used when the
                        group's users place or receive calls.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Group identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for internal calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for external calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_outside_the_group:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension displayed to non-group members'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Default caller identity applied to the group's outbound calls"
                          example: 550e8400-e29b-41d4-a716-446655440004
                        external_uid:
                          type:
                            - string
                            - 'null'
                          description: 'External identifier from a CRM or directory sync'
                          example: grp-support
                        allow_call_pickups:
                          type: boolean
                          description: "Whether group members may pick up each others' ringing calls"
                          example: true
                        name:
                          type: string
                          maxLength: 64
                          example: 'Support team'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'First-line support'
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: "Whether the group's CIDs include the PBX-default outbound numbers"
                          example: false
                        display_tab_to_everyone_inside_voxbi:
                          type: boolean
                          description: "Whether the group's tab is shown to everyone in the PBX"
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        users:
                          type: array
                          description: |
                            Members of the group, each as a user reference. Returned only when
                            requested via `?include=users`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                  allow_access_to_group_contacts:
                    type: array
                    description: |
                      Groups whose contacts the user may access. Returned only when requested
                      via `?include=allowAccessToGroupContacts`.
                    items:
                      type: object
                      description: |
                        Group of users that share routing defaults and (optionally) a common caller
                        identity. Many fields are foreign keys pointing at defaults used when the
                        group's users place or receive calls.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Group identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        default_internal_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for internal calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        default_external_call_flow_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Call flow used for external calls reaching this group'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_outside_the_group:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Extension displayed to non-group members'
                          example: 550e8400-e29b-41d4-a716-446655440005
                        default_caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Default caller identity applied to the group's outbound calls"
                          example: 550e8400-e29b-41d4-a716-446655440004
                        external_uid:
                          type:
                            - string
                            - 'null'
                          description: 'External identifier from a CRM or directory sync'
                          example: grp-support
                        allow_call_pickups:
                          type: boolean
                          description: "Whether group members may pick up each others' ringing calls"
                          example: true
                        name:
                          type: string
                          maxLength: 64
                          example: 'Support team'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'First-line support'
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: "Whether the group's CIDs include the PBX-default outbound numbers"
                          example: false
                        display_tab_to_everyone_inside_voxbi:
                          type: boolean
                          description: "Whether the group's tab is shown to everyone in the PBX"
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        users:
                          type: array
                          description: |
                            Members of the group, each as a user reference. Returned only when
                            requested via `?include=users`.
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                                example: 550e8400-e29b-41d4-a716-446655440006
                                readOnly: true
                              first_name:
                                type:
                                  - string
                                  - 'null'
                                example: Jane
                              last_name:
                                type:
                                  - string
                                  - 'null'
                                example: Smith
                              email:
                                type:
                                  - string
                                  - 'null'
                                format: email
                                example: jane.smith@example.com
                  sip_devices:
                    type: array
                    description: 'SIP devices assigned to the user. Returned only when requested via `?include=sipDevices`.'
                    items:
                      type: object
                      description: |
                        Physical or soft SIP endpoint (deskphone, softphone, ATA, trunk) registered
                        against the PBX. The device owner is exposed as a friendly `target_type`
                        (`user` / `extension`) plus `target_id`; the full `target` object is opt-in.
                        The SIP password is never exposed.
                      required:
                        - id
                        - pbx_id
                        - name
                        - is_enabled
                        - type
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'SIP device identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        target_type:
                          type:
                            - string
                            - 'null'
                          description: 'Friendly type of the entity the device is assigned to'
                          enum:
                            - user
                            - extension
                          example: user
                        target_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Identifier of the target entity'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        extension_id_shown_for_internal_calls:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: "Extension displayed in the device's caller ID for internal calls"
                          example: null
                        roaming_user_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'User currently roamed onto this device'
                          example: null
                        location_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Physical location the device is installed at'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        parent_sip_device_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Parent device (e.g. a Gigaset base) for handset child devices'
                          example: null
                        name:
                          type: string
                          maxLength: 128
                          example: 'Reception desk phone'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Front-desk Yealink T46U'
                        is_enabled:
                          type: boolean
                          description: 'Whether the device is currently enabled'
                          example: true
                        ip_internal:
                          type:
                            - string
                            - 'null'
                          description: 'Last-seen internal IP'
                          example: 192.168.1.42
                        ip_external:
                          type:
                            - string
                            - 'null'
                          description: 'Last-seen external IP'
                          example: 203.0.113.10
                        user_agent:
                          type:
                            - string
                            - 'null'
                          description: 'SIP User-Agent string reported by the device'
                          example: 'Yealink SIP-T46U 108.86.0.10'
                        mac:
                          type:
                            - string
                            - 'null'
                          description: 'MAC address'
                          example: '00:0a:95:9d:68:16'
                        vlan_phone:
                          type:
                            - integer
                            - 'null'
                          description: 'VLAN id for the phone interface'
                          example: 100
                        vlan_pc:
                          type:
                            - integer
                            - 'null'
                          description: 'VLAN id for the PC pass-through interface'
                          example: 200
                        sip_username:
                          type:
                            - string
                            - 'null'
                          maxLength: 24
                          description: 'SIP authentication username'
                          example: device_001
                        alt_username:
                          type:
                            - string
                            - 'null'
                          description: 'Alternate SIP username (used for multi-line registrations)'
                          example: null
                        transport:
                          type: string
                          description: 'SIP transport'
                          enum:
                            - udp
                            - tcp
                            - tls
                          example: tls
                        type:
                          type: string
                          description: 'Device provisioning category'
                          enum:
                            - auto
                            - manual
                            - gigaset
                            - trunk
                          example: auto
                        allow_roaming:
                          type: boolean
                          description: 'Whether the device accepts roamed-in users'
                          example: false
                        language:
                          type: string
                          description: 'Display language for the device'
                          example: en
                        easy_deploy:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp until which the device is in easy-deploy mode'
                          example: null
                        notify:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp at which a SIP NOTIFY was last requested'
                          example: null
                        allow_default_pbxes_outgoing_phone_numbers:
                          type: boolean
                          description: 'Whether the PBX default outbound numbers are usable from this device'
                          example: false
                        sync_source:
                          type: string
                          description: 'Provisioning origin'
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          example: provision
                        custom_provisioning:
                          type:
                            - string
                            - 'null'
                          description: 'Custom provisioning template snippet'
                          example: null
                        last_seen:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Last time the device registered'
                          example: '2024-03-01T08:29:07Z'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        target:
                          type: object
                          description: |
                            The resolved device owner (a user or an extension); shape varies by
                            `target_type`. Returned only when requested via `?include=target`.
                        tags:
                          type: array
                          description: 'Tags attached to this device. Returned only when requested via `?include=tags`.'
                          items:
                            type: object
                            description: |
                              Free-form label that can be attached to users, SIP devices, phone numbers, and
                              other tenant resources for grouping, filtering, and reporting. Tags are scoped
                              to a single Pbx (tenant). Associations to the resources a tag is applied to are
                              held on the relevant pivot tables, not on this schema.
                            required:
                              - id
                              - pbx_id
                              - name
                            properties:
                              id:
                                type: string
                                format: uuid
                                description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                                example: 550e8400-e29b-41d4-a716-446655440000
                                readOnly: true
                              pbx_id:
                                type: string
                                format: uuid
                                description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                                example: 550e8400-e29b-41d4-a716-446655440001
                                readOnly: true
                              name:
                                type: string
                                maxLength: 64
                                description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                                example: 'VIP Customers'
                              description:
                                type:
                                  - string
                                  - 'null'
                                maxLength: 255
                                description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                                example: 'Customers with priority routing and dedicated agents.'
                              created_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                              updated_at:
                                type:
                                  - string
                                  - 'null'
                                format: date-time
                                description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                                example: '2024-03-01T08:29:07Z'
                                readOnly: true
                        caller_identities:
                          type: array
                          description: |
                            Caller identities available to this device. Returned only when requested
                            via `?include=callerIdentities`.
                          items:
                            type: object
                        location:
                          description: |
                            The resolved installation location. Returned only when requested via
                            `?include=location`.
                          allOf:
                            -
                              type: object
                              description: |
                                Physical office or site associated with a PBX. Locations form a nested-set
                                tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                                used for emergency call routing.
                              required:
                                - id
                                - pbx_id
                                - name
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                  description: 'Location identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440000
                                  readOnly: true
                                pbx_id:
                                  type: string
                                  format: uuid
                                  description: 'Pbx identifier (tenant)'
                                  example: 550e8400-e29b-41d4-a716-446655440001
                                company_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Owning company identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440004
                                parent_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Parent location identifier in the nested-set tree'
                                  example: 550e8400-e29b-41d4-a716-446655440002
                                name:
                                  type: string
                                  maxLength: 64
                                  example: 'Luxembourg HQ'
                                description:
                                  type:
                                    - string
                                    - 'null'
                                  maxLength: 255
                                  example: 'Main office, 5th floor'
                                street_no:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Street number portion of the address'
                                  example: '12'
                                street:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Main Street'
                                city:
                                  type:
                                    - string
                                    - 'null'
                                  example: Luxembourg
                                postal:
                                  type:
                                    - string
                                    - 'null'
                                  description: 'Postal code'
                                  example: '1234'
                                country_id:
                                  type:
                                    - string
                                    - 'null'
                                  format: uuid
                                  description: 'Country identifier'
                                  example: 550e8400-e29b-41d4-a716-446655440003
                                lft:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Nested-set left bound'
                                  example: 1
                                rgt:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Nested-set right bound'
                                  example: 10
                                depth:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Tree depth (0 for root locations)'
                                  example: 0
                                enable_location_as_presence_status:
                                  type: boolean
                                  description: 'Whether this location can be used as a presence status value'
                                  example: false
                                style:
                                  type:
                                    - object
                                    - 'null'
                                  description: 'Optional presentation style (badge icon and colours) for the location'
                                  example:
                                    icon_class: la-map-pin
                                    bg_color: '#3490dc'
                                    font_color: '#ffffff'
                                is_fixed_location:
                                  type: boolean
                                  description: 'Whether this is a fixed (geofenced) physical location'
                                  example: true
                                latitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: float
                                  description: 'Latitude of the location, in decimal degrees'
                                  example: 49.6116
                                longitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: float
                                  description: 'Longitude of the location, in decimal degrees'
                                  example: 6.1319
                                geofence_radius_m:
                                  type:
                                    - integer
                                    - 'null'
                                  description: 'Geofence radius around the location, in metres'
                                  example: 100
                                created_at:
                                  type:
                                    - string
                                    - 'null'
                                  format: date-time
                                  example: '2024-03-01T08:29:07Z'
                                  readOnly: true
                                updated_at:
                                  type:
                                    - string
                                    - 'null'
                                  format: date-time
                                  example: '2024-03-01T08:29:07Z'
                                  readOnly: true
                  twinnings:
                    type: array
                    description: 'Twinnings configured for the user. Returned only when requested via `?include=twinnings`.'
                    items:
                      type: object
                      description: |
                        Twinning: an external destination that rings alongside a user's extension
                        (a mobile phone or a Microsoft Teams endpoint). When a call reaches the user,
                        the twinned destination rings in parallel so the call can be answered away
                        from the desk phone. Tenant scoping is derived from the attached user; this
                        resource has no direct `pbx_id` column of its own.
                      required:
                        - id
                        - user_id
                        - status
                        - phone_number
                        - delay
                        - sync_source
                        - type
                        - dial_strategy
                        - fmc_enabled
                        - backup_phone_number
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the twinning.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        user_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the user this twinning belongs to. The user also determines the PBX tenant this twinning is scoped to.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        status:
                          type: string
                          enum:
                            - enabled
                            - disabled
                          description: "Whether the twinning is active. Only an enabled twinning rings alongside the user's extension."
                          example: enabled
                        phone_number:
                          type:
                            - string
                            - 'null'
                          description: 'The twinned destination phone number, stored in E.164 format. Null when the twinning targets a Teams endpoint or has no number configured.'
                          example: '+12125550100'
                        delay:
                          type: integer
                          format: int32
                          minimum: 0
                          description: 'Number of seconds to wait after the call starts before the twinning leg begins ringing. A value of 0 means it rings immediately.'
                          example: 5
                        sync_source:
                          type: string
                          enum:
                            - manual
                            - provision
                            - legacy_import
                          description: 'Origin of this twinning record. `manual` was created by a user, `provision` came from an automated provisioning step, and `legacy_import` was migrated from a previous system.'
                          example: manual
                        type:
                          type: string
                          enum:
                            - mobile
                            - teams
                          description: 'Channel used to reach the twinned destination, either a mobile phone or a Microsoft Teams endpoint.'
                          example: mobile
                        dial_strategy:
                          type: string
                          enum:
                            - gsm_only
                            - voip_only
                            - voip_and_gsm_fallback
                          description: |
                            How the mobile leg is dialed: `gsm_only` uses the cellular network only,
                            `voip_only` uses the VoIP app only, and `voip_and_gsm_fallback` tries
                            VoIP first and falls back to GSM. Only meaningful for mobile-type
                            twinnings that use the Fixed-Mobile Convergence (FMC) integration.
                          example: voip_and_gsm_fallback
                        fmc_enabled:
                          type: boolean
                          description: 'Whether Fixed-Mobile Convergence (FMC) is enabled for this twinning, allowing seamless handover between VoIP and the cellular network.'
                          example: false
                        backup_phone_number:
                          type:
                            - string
                            - 'null'
                          description: 'Secondary phone number, in E.164 format, dialed when the primary FMC leg cannot be reached. Null when no backup is configured.'
                          example: '+12125550101'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the twinning was created (ISO 8601, UTC).'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp when the twinning was last updated (ISO 8601, UTC).'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  caller_identities:
                    type: array
                    description: |
                      Effective (inherited) caller identities for the user: own plus those of
                      the user's groups plus the PBX's. Returned only when requested via
                      `?include=callerIdentities`.
                    items:
                      type: object
                  locations:
                    type: array
                    description: 'Locations the user is associated with. Returned only when requested via `?include=locations`.'
                    items:
                      type: object
                      description: |
                        Physical office or site associated with a PBX. Locations form a nested-set
                        tree via `parent_id` + `lft`/`rgt`/`depth`. Street-level address fields are
                        used for emergency call routing.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Location identifier'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Pbx identifier (tenant)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        company_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Owning company identifier'
                          example: 550e8400-e29b-41d4-a716-446655440004
                        parent_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Parent location identifier in the nested-set tree'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        name:
                          type: string
                          maxLength: 64
                          example: 'Luxembourg HQ'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          example: 'Main office, 5th floor'
                        street_no:
                          type:
                            - string
                            - 'null'
                          description: 'Street number portion of the address'
                          example: '12'
                        street:
                          type:
                            - string
                            - 'null'
                          example: 'Main Street'
                        city:
                          type:
                            - string
                            - 'null'
                          example: Luxembourg
                        postal:
                          type:
                            - string
                            - 'null'
                          description: 'Postal code'
                          example: '1234'
                        country_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Country identifier'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        lft:
                          type:
                            - integer
                            - 'null'
                          description: 'Nested-set left bound'
                          example: 1
                        rgt:
                          type:
                            - integer
                            - 'null'
                          description: 'Nested-set right bound'
                          example: 10
                        depth:
                          type:
                            - integer
                            - 'null'
                          description: 'Tree depth (0 for root locations)'
                          example: 0
                        enable_location_as_presence_status:
                          type: boolean
                          description: 'Whether this location can be used as a presence status value'
                          example: false
                        style:
                          type:
                            - object
                            - 'null'
                          description: 'Optional presentation style (badge icon and colours) for the location'
                          example:
                            icon_class: la-map-pin
                            bg_color: '#3490dc'
                            font_color: '#ffffff'
                        is_fixed_location:
                          type: boolean
                          description: 'Whether this is a fixed (geofenced) physical location'
                          example: true
                        latitude:
                          type:
                            - number
                            - 'null'
                          format: float
                          description: 'Latitude of the location, in decimal degrees'
                          example: 49.6116
                        longitude:
                          type:
                            - number
                            - 'null'
                          format: float
                          description: 'Longitude of the location, in decimal degrees'
                          example: 6.1319
                        geofence_radius_m:
                          type:
                            - integer
                            - 'null'
                          description: 'Geofence radius around the location, in metres'
                          example: 100
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  languages:
                    type: array
                    description: 'Languages the user is associated with. Returned only when requested via `?include=languages`.'
                    items:
                      type: object
                      description: |
                        A language defined for the tenant, used to label sound files, voice prompts
                        (IVR announcements), and per-user language preferences. Each language belongs
                        to exactly one Pbx (tenant) and is identified by a free-text name.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique language identifier (UUID).'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this language.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                          readOnly: true
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable language name as shown in the cockpit and selectors.'
                          example: English
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the language was created. Null if not set.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the language was last updated. Null if not set.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  tags:
                    type: array
                    description: 'Tags attached to the user. Returned only when requested via `?include=tags`.'
                    items:
                      type: object
                      description: |
                        Free-form label that can be attached to users, SIP devices, phone numbers, and
                        other tenant resources for grouping, filtering, and reporting. Tags are scoped
                        to a single Pbx (tenant). Associations to the resources a tag is applied to are
                        held on the relevant pivot tables, not on this schema.
                      required:
                        - id
                        - pbx_id
                        - name
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique tag identifier (UUID), assigned by the server on creation.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this tag. Tags are never shared across tenants.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                          readOnly: true
                        name:
                          type: string
                          maxLength: 64
                          description: 'Human-readable label for the tag, shown in dropdowns and used when filtering tagged resources.'
                          example: 'VIP Customers'
                        description:
                          type:
                            - string
                            - 'null'
                          maxLength: 255
                          description: 'Optional free-text note explaining the purpose of the tag. Null when no description was provided.'
                          example: 'Customers with priority routing and dedicated agents.'
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was created.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Timestamp (ISO 8601, UTC) when the tag was last modified.'
                          example: '2024-03-01T08:29:07Z'
                          readOnly: true
                  queues:
                    type: array
                    description: 'Queues the user is a member of. Returned only when requested via `?include=queues`.'
                    items:
                      type: object
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{email}/webrtc':
    get:
      tags:
        - Users
      summary: 'Get an user WebRTC configuration by Email'
      operationId: getUserWebrtc
      security:
        -
          ApiKeyAuth: {}
      description: |
        Returns the user webrtc identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: email
          in: path
          schema:
            type: string
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  hostname:
                    type: string
                    example: pbx.mixvoip.com
                  port:
                    type: integer
                    example: 8089
                  username:
                    type: string
                    example: mixvoip_webrtc_1337
                  password:
                    type: string
                    example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
                  caller_identities:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        root_phone_nuber_id:
                          type: integer
                          example: 1
                        external_caller_extension:
                          type: string
                          example: '1337'
                        external_caller_number:
                          type: string
                          example: '2033331337'
                  allow_anonymous_calls:
                    type: boolean
                    example: true
                  allow_call_forwarding:
                    type: boolean
                    example: true
                  allow_change_twinning_dest:
                    type: boolean
                    example: true
                  allow_dnd:
                    type: boolean
                    example: true
                  allow_status_changer:
                    type: boolean
                    example: true
                  call_information_visibility:
                    type: string
                    example: own_calls
                    enum:
                      - own_calls
                      - own_group_only
                      - none
                  call_pickpup_restrictions:
                    type: string
                    example: 'yes'
                    enum:
                      - 'yes'
                      - own_groups_only
                      - 'no'
                  voicemail:
                    type: boolean
                    example: true
                  voicemail_destination:
                    type: string
                    example: email_only
                    enum:
                      - email_only
                      - email_and_phone
                  voicemail_pin:
                    type: string
                    example: '1234'
                  voicemail_type:
                    type: string
                    example: enabled
                    enum:
                      - enabled
                      - external
                      - internal
              example:
                hostname: pbx.mixvoip.com
                port: 8089
                username: mixvoip_webrtc_1337
                password: $2y$10$ePs3A38yC.ewAqS0CVLghuLvimTIm5Pf0HUw5155wM9wd16XVqpeS
                caller_identities:
                  -
                    id: 1
                    root_phone_nuber_id: 1
                    external_caller_extension: '1337'
                    external_caller_number: '2033331337'
                allow_anonymous_calls: true
                allow_call_forwarding: true
                allow_change_twinning_dest: true
                allow_dnd: true
                allow_status_changer: true
                call_information_visibility: own_calls
                call_pickpup_restrictions: 'yes'
                voicemail: true
                voicemail_destination: email_only
                voicemail_pin: '1234'
                voicemail_type: enabled
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /qr-code:
    get:
      tags:
        - Users
      summary: 'Get QR code for authenticated user'
      operationId: getUserQrCode
      description: |
        Returns a paginated list of user qr code. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      qr_code:
                        type: string
                        description: 'Base64-encoded QR code image'
                        example: 'data:image/png;base64,iVBORw0KGgo='
              example:
                data:
                  qr_code: 'data:image/png;base64,iVBORw0KGgo='
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /soop-status:
    get:
      tags:
        - Users
      summary: 'Get SOOP status for authenticated user'
      operationId: getUserSoopStatus
      description: |
        Returns a paginated list of user soop status. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      status:
                        type: string
                        example: online
                      sub_status:
                        type:
                          - string
                          - 'null'
                        example: in_meeting
                      updated_at:
                        type: string
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
              example:
                data:
                  status: online
                  sub_status: null
                  updated_at: '2023-10-17T14:12:22Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /favorites:
    post:
      tags:
        - Users
      summary: 'Toggle favorite user'
      operationId: postUserFavorites
      description: |
        Creates a new user favorites. Validation rules and required fields are defined in the
        request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_id
              properties:
                user_id:
                  type: string
                  description: 'UUID of the user to toggle as favorite'
                  example: 550e8400-e29b-41d4-a716-446655440000
            example:
              user_id: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      favorited:
                        type: boolean
                        description: 'Whether the user is now a favorite (true) or was removed (false)'
                        example: true
              example:
                data:
                  favorited: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /poll:
    get:
      tags:
        - Users
      summary: 'Poll extensions with DND, status and in-call flags (user)'
      operationId: getUserPoll
      description: |
        Live board for every extension in the authenticated user's PBX whose extension is
        linked to a user: current Tempus status, sub-statuses, DND, the in-call flag and,
        for employees currently on leave, when they are next available.

        The response is NOT a list and is NOT paginated: it is a single object keyed by
        Cockpit user id, so a client can look a user up directly. Responses are cached per
        PBX for a few seconds, so a change made through another endpoint (for example
        `POST /in-call`) surfaces here within that window rather than instantly.

        `in_call` is owned by Cockpit and comes from what the user's own client last reported
        to `POST /in-call`. It is independent of whether the user has a running Tempus
        timepoint, and a `true` decays to `false` after an hour if the hang-up is never
        reported. `updated_at` is the status/timepoint change time, which is a different
        thing from `in_call_updated_at`.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                description: "Map of Cockpit user id to that user's live board entry."
                additionalProperties:
                  type: object
                  properties:
                    cockpit_user_id:
                      type: string
                      format: uuid
                      description: 'The Cockpit user the extension belongs to.'
                    cockpit_status_id:
                      type:
                        - string
                        - 'null'
                      format: uuid
                      description: 'Current Tempus status id in Cockpit.'
                    cockpit_status:
                      type:
                        - string
                        - 'null'
                      description: 'Current Tempus status name.'
                    sub_statuses:
                      type: array
                      description: 'Sub-statuses attached to the current status.'
                      items:
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                          name:
                            type: string
                    number:
                      type: string
                      description: 'Extension number.'
                    extintenabled:
                      type: boolean
                      description: 'Always true; kept for backwards compatibility.'
                    status_id:
                      type:
                        - string
                        - integer
                        - 'null'
                      description: 'Phone-system status mapping id, falling back to the Cockpit status id.'
                    substatus_id:
                      type:
                        - string
                        - 'null'
                      description: 'Reserved; always null.'
                    user_id:
                      type: string
                      format: uuid
                      description: 'Deprecated alias of `pbx_id`. Use `pbx_id`.'
                    pbx_id:
                      type: string
                      format: uuid
                      description: 'The PBX the extension belongs to.'
                    payable:
                      type: boolean
                      description: 'Whether the current status counts as paid time.'
                    in_call:
                      type: boolean
                      description: |
                        Whether the user is on a call right now, as last reported by their client
                        through `POST /in-call`. Expires back to false after an hour.
                    in_call_updated_at:
                      type:
                        - string
                        - 'null'
                      format: date-time
                      description: 'When `in_call` was last reported, null when nothing is reported.'
                    updated_at:
                      type:
                        - string
                        - 'null'
                      format: date-time
                      description: 'When the current status last changed. Unrelated to `in_call_updated_at`.'
                    dnd:
                      oneOf:
                        -
                          type: boolean
                        -
                          type: array
                          items:
                            type: object
                      description: 'false when the user has no DND rows, otherwise their DND settings.'
                    id:
                      type:
                        - string
                        - integer
                        - 'null'
                      description: 'Phone-system extension-status row id, when the status came from there.'
                    location_id:
                      type:
                        - string
                        - 'null'
                      format: uuid
                      description: "Location on the user's latest timepoint."
                    next_availability:
                      type:
                        - object
                        - 'null'
                      description: |
                        Set only for active-contract employees who are unavailable right now because
                        of an absence: when they are back, plus a ready-to-display message.
                      properties:
                        next_available_date:
                          type: string
                          format: date
                        next_available_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        message:
                          type: string
                        reason:
                          type:
                            - string
                            - 'null'
                        absence:
                          type:
                            - object
                            - 'null'
                        absence_window:
                          type:
                            - object
                            - 'null'
              example:
                550e8400-e29b-41d4-a716-446655440000:
                  cockpit_user_id: 550e8400-e29b-41d4-a716-446655440000
                  cockpit_status_id: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  cockpit_status: Working
                  sub_statuses:
                    -
                      id: 6ba7b811-9dad-11d1-80b4-00c04fd430c8
                      name: Office
                  number: '101'
                  extintenabled: true
                  status_id: 3
                  substatus_id: null
                  user_id: 6ba7b812-9dad-11d1-80b4-00c04fd430c8
                  pbx_id: 6ba7b812-9dad-11d1-80b4-00c04fd430c8
                  payable: true
                  in_call: true
                  in_call_updated_at: '2026-08-03T09:14:22+00:00'
                  updated_at: '2026-08-03T08:00:00+00:00'
                  dnd: false
                  id: null
                  location_id: null
                  next_availability: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /in-call:
    get:
      tags:
        - Users
      summary: "Read the authenticated user's in-call flag (user)"
      operationId: getUserInCall
      description: |
        Returns whether the authenticated user is currently reported as being on a call,
        plus when that was last reported. The flag is owned by Cockpit: it is whatever the
        client last sent to `POST /in-call`.

        A flag set to `true` is trusted for a limited window only (`ttl_seconds`, one hour by
        default). Past that window it decays back to `false` on its own, so a client that
        never gets to report the hang-up (crash, network loss, killed app) cannot leave the
        user marked in-call forever. `in_call_updated_at` and `expires_at` are `null` when
        nothing has been reported inside the window.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/InCallState'
              example:
                data:
                  user_id: 550e8400-e29b-41d4-a716-446655440000
                  in_call: true
                  in_call_updated_at: '2026-08-03T09:14:22+00:00'
                  expires_at: '2026-08-03T10:14:22+00:00'
                  ttl_seconds: 3600
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
    post:
      tags:
        - Users
      summary: "Set the authenticated user's in-call flag (user)"
      operationId: postUserInCall
      description: |
        Reports whether the authenticated user is on a call right now: send `true` when the
        call starts and `false` when it ends. The user is always taken from the bearer token,
        so this endpoint can never change anyone else's flag.

        The call is idempotent: sending the same value again simply refreshes the timestamp
        and pushes the expiry window out. Sending `false` clears the flag immediately, and a
        `true` that is never cleared expires by itself after `ttl_seconds` (one hour by
        default), so it is safe to miss a hang-up report.

        The new value is served by `GET /poll` (as `in_call` and `in_call_updated_at`) within
        the poll's own short cache window of a few seconds.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - in_call
              properties:
                in_call:
                  type: boolean
                  description: 'true while the user is on a call, false once it has ended.'
                  example: true
            example:
              in_call: true
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/InCallState'
              example:
                data:
                  user_id: 550e8400-e29b-41d4-a716-446655440000
                  in_call: true
                  in_call_updated_at: '2026-08-03T09:14:22+00:00'
                  expires_at: '2026-08-03T10:14:22+00:00'
                  ttl_seconds: 3600
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Content. `in_call` is missing or is not a boolean.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  errors:
                    type: object
                    properties:
                      in_call:
                        type: array
                        items:
                          type: string
              example:
                message: 'The in call field is required.'
                errors:
                  in_call:
                    - 'The in call field is required.'
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
  /user/devices:
    get:
      tags:
        - Users
      summary: 'List devices for authenticated user'
      operationId: listUserDevices
      description: |
        Returns a paginated list of user devices. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: type
          in: query
          required: false
          schema:
            type: string
          description: 'Filter by device type'
          example: fcm
        -
          name: active
          in: query
          required: false
          schema:
            type: boolean
          description: 'Filter by active status'
          example: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Devices retrieved successfully'
                  devices:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440070
                        name:
                          type:
                            - string
                            - 'null'
                          example: 'My iPhone'
                        user_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        twinning_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: null
                        type:
                          type: string
                          example: fcm
                        token:
                          type: string
                          example: abc123xyz...
                        is_active:
                          type: boolean
                          example: true
                        last_used_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2023-10-17T14:12:22Z'
                        created_at:
                          type: string
                          format: date-time
                          example: '2023-10-01T10:00:00Z'
                        updated_at:
                          type: string
                          format: date-time
                          example: '2023-10-17T14:12:22Z'
                  total:
                    type: integer
                    example: 1
              example:
                message: 'Devices retrieved successfully'
                devices:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440070
                    name: 'My iPhone'
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    twinning_id: null
                    type: fcm
                    token: abc123xyz...
                    is_active: true
                    last_used_at: '2023-10-17T14:12:22Z'
                    created_at: '2023-10-01T10:00:00Z'
                    updated_at: '2023-10-17T14:12:22Z'
                total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
    post:
      tags:
        - Users
      summary: 'Register a device for authenticated user'
      operationId: createUserDevice
      description: |
        Creates a new user device. Validation rules and required fields are defined in the request
        body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - token
              properties:
                name:
                  type:
                    - string
                    - 'null'
                  description: 'Optional device name'
                  example: 'My iPhone'
                type:
                  type: string
                  description: 'Device type (e.g. fcm, apns)'
                  example: fcm
                token:
                  type: string
                  description: 'Device push token'
                  example: abc123xyz...
            example:
              name: 'My iPhone'
              type: fcm
              token: abc123xyz...
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'Device updated (token already existed)'
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Device updated successfully'
                  device:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440070
                      name:
                        type:
                          - string
                          - 'null'
                        example: 'My iPhone'
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      twinning_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        example: null
                      type:
                        type: string
                        example: fcm
                      token:
                        type: string
                        example: abc123xyz...
                      is_active:
                        type: boolean
                        example: true
                      last_used_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
                      created_at:
                        type: string
                        format: date-time
                        example: '2023-10-01T10:00:00Z'
                      updated_at:
                        type: string
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
              example:
                message: 'Device updated successfully'
                device:
                  id: 550e8400-e29b-41d4-a716-446655440070
                  name: 'My iPhone'
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  twinning_id: null
                  type: fcm
                  token: abc123xyz...
                  is_active: true
                  last_used_at: '2023-10-17T14:12:22Z'
                  created_at: '2023-10-01T10:00:00Z'
                  updated_at: '2023-10-17T14:12:22Z'
        201:
          description: 'Device registered successfully'
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Device registered successfully'
                  device:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440070
                      name:
                        type:
                          - string
                          - 'null'
                        example: 'My iPhone'
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      twinning_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        example: null
                      type:
                        type: string
                        example: fcm
                      token:
                        type: string
                        example: abc123xyz...
                      is_active:
                        type: boolean
                        example: true
                      last_used_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
                      created_at:
                        type: string
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
                      updated_at:
                        type: string
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
              example:
                message: 'Device registered successfully'
                device:
                  id: 550e8400-e29b-41d4-a716-446655440070
                  name: 'My iPhone'
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  twinning_id: null
                  type: fcm
                  token: abc123xyz...
                  is_active: true
                  last_used_at: '2023-10-17T14:12:22Z'
                  created_at: '2023-10-17T14:12:22Z'
                  updated_at: '2023-10-17T14:12:22Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/user/devices/{deviceIdOrToken}':
    patch:
      tags:
        - Users
      summary: 'Update a device for authenticated user'
      operationId: updateUserDevice
      description: |
        Partially updates the user device. Only the fields supplied in the request body are changed;
        others are left untouched.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: deviceIdOrToken
          in: path
          required: true
          schema:
            type: string
          description: 'Device UUID or push token'
          example: 550e8400-e29b-41d4-a716-446655440070
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type:
                    - string
                    - 'null'
                  description: 'New device name'
                  example: 'My Android'
                is_active:
                  type:
                    - boolean
                    - 'null'
                  description: 'Whether the device should be active'
                  example: false
            example:
              name: 'My Android'
              is_active: false
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Device updated successfully'
                  device:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440070
                      name:
                        type:
                          - string
                          - 'null'
                        example: 'My Android'
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      twinning_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        example: null
                      type:
                        type: string
                        example: fcm
                      token:
                        type: string
                        example: abc123xyz...
                      is_active:
                        type: boolean
                        example: false
                      last_used_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
                      created_at:
                        type: string
                        format: date-time
                        example: '2023-10-01T10:00:00Z'
                      updated_at:
                        type: string
                        format: date-time
                        example: '2023-10-17T14:12:22Z'
              example:
                message: 'Device updated successfully'
                device:
                  id: 550e8400-e29b-41d4-a716-446655440070
                  name: 'My Android'
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  twinning_id: null
                  type: fcm
                  token: abc123xyz...
                  is_active: false
                  last_used_at: '2023-10-17T14:12:22Z'
                  created_at: '2023-10-01T10:00:00Z'
                  updated_at: '2023-10-17T14:12:22Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Users
      summary: 'Delete a device for authenticated user'
      operationId: deleteUserDevice
      description: |
        Deletes the user device. Soft-delete behaviour is model-dependent: most resources are
        recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: deviceIdOrToken
          in: path
          required: true
          schema:
            type: string
          description: 'Device UUID or push token'
          example: 550e8400-e29b-41d4-a716-446655440070
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Device deleted successfully'
              example:
                message: 'Device deleted successfully'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /dnd:
    post:
      tags:
        - Users
      summary: 'Set User DND'
      operationId: postUserDnd
      security:
        -
          PbxServerAuth: {}
      description: |
        Triggers the action on the targeted user dnd.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  user_id:
                    type: integer
                    example: 1
                  caller_identity_id:
                    type: integer
                    example: 1
                  extension_id:
                    type: integer
                    example: 1
                  status:
                    type: boolean
                    example: false
                  id:
                    type: integer
                    example: 1
              example:
                id: 1
                user_id: 1
                caller_identity_id: 1
                extension_id: 1
                status: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /dnds:
    get:
      tags:
        - DND
      summary: 'List DND rules for the authenticated user'
      operationId: listDnds
      description: |
        Returns a paginated list of dnds. Use the standard `search`, `sort`, `page`, and `perPage`
        query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant scoping is
        enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        pbx_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440002
                        user_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        caller_identity_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Caller identity the rule applies to (null for the internal-extension rule)'
                          example: 550e8400-e29b-41d4-a716-446655440003
                        type:
                          type: string
                          enum:
                            - internal
                            - external
                          example: external
                        status:
                          type: boolean
                          example: false
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          readOnly: true
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          readOnly: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440002
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    caller_identity_id: 550e8400-e29b-41d4-a716-446655440003
                    type: external
                    status: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  '/users/{user}/dnds':
    get:
      tags:
        - DND
      summary: 'List DNDs for a user'
      operationId: getDndUserDndsIndex
      description: |
        Returns the dnd user dnds index identified by the path parameter. Multi-tenant scoping is
        enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        user_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        caller_identity_id:
                          type:
                            - integer
                            - 'null'
                          example: 1
                        extension_id:
                          type:
                            - integer
                            - 'null'
                          example: 1
                        status:
                          type: boolean
                          example: false
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    caller_identity_id: 1
                    extension_id: 1
                    status: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - DND
      summary: 'Create a DND for a user'
      operationId: postDndUserDndsIndex
      description: |
        Creates a new dnd user dnds index. Validation rules and required fields are defined in the
        request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - status
              properties:
                type:
                  type: string
                  enum:
                    - internal
                    - external
                  description: |
                    `internal` toggles DND on the user's internal extension; `external`
                    toggles a per-caller-identity rule. When `type=external`, `caller_identity_id` is required.
                  example: external
                caller_identity_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Required when `type=external`. Omit when `type=internal`.'
                  example: 550e8400-e29b-41d4-a716-446655440003
                status:
                  type: boolean
                  description: 'Whether DND is enabled'
                  example: true
            example:
              type: external
              caller_identity_id: 550e8400-e29b-41d4-a716-446655440003
              status: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440000
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      caller_identity_id:
                        type:
                          - integer
                          - 'null'
                        example: 1
                      extension_id:
                        type:
                          - integer
                          - 'null'
                        example: 1
                      status:
                        type: boolean
                        example: false
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  caller_identity_id: 1
                  extension_id: 1
                  status: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/dnds/{userDnd}':
    put:
      tags:
        - DND
      summary: 'Update a DND for a user'
      operationId: updateDndUserDndsSpecific
      description: |
        Replaces the dnd user dnds specific with the fields supplied in the request body. Fields
        omitted from the body are reset to their defaults.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: dnd
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the DND'
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              description: 'Update only accepts toggling `status`; other fields are ignored.'
              properties:
                status:
                  type: boolean
                  description: 'Whether DND should be enabled'
                  example: true
            example:
              status: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440000
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      caller_identity_id:
                        type:
                          - integer
                          - 'null'
                        example: 1
                      extension_id:
                        type:
                          - integer
                          - 'null'
                        example: 1
                      status:
                        type: boolean
                        example: true
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  caller_identity_id: 1
                  extension_id: 1
                  status: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/dnds/bulk':
    post:
      tags:
        - DND
      summary: 'Bulk-update DND rules for a user'
      operationId: postDndUserDndsBulk
      description: |
        Creates a new dnd user dnds bulk. Validation rules and required fields are defined in the
        request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - dnds
              properties:
                dnds:
                  type: array
                  description: 'Array of DND rules to apply'
                  items:
                    type: object
                    required:
                      - type
                      - status
                    properties:
                      type:
                        type: string
                        enum:
                          - internal
                          - external
                      caller_identity_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Required when `type=external`'
                      status:
                        type: boolean
            example:
              dnds:
                -
                  type: internal
                  status: true
                -
                  type: external
                  caller_identity_id: 550e8400-e29b-41d4-a716-446655440003
                  status: false
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440000
                        status:
                          type: boolean
                          example: true
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    status: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/dnds/all-external':
    post:
      tags:
        - DND
      summary: 'Toggle DND on every external extension of a user'
      operationId: postDndUserDndsAllExternal
      description: |
        Creates a new dnd user dnds all external. Validation rules and required fields are defined
        in the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: boolean
                  description: 'DND status to apply to all external extensions'
                  example: true
            example:
              status: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      updated:
                        type: integer
                        description: 'Number of DND records updated'
                        example: 3
              example:
                data:
                  updated: 3
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/dnds/all':
    post:
      tags:
        - DND
      summary: 'Toggle DND on every extension of a user'
      operationId: postDndUserDndsAll
      description: |
        Creates a new dnd user dnds all. Validation rules and required fields are defined in the
        request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: boolean
                  description: 'DND status to apply to all extensions'
                  example: true
            example:
              status: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      updated:
                        type: integer
                        description: 'Number of DND records updated'
                        example: 5
              example:
                data:
                  updated: 5
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/forwards':
    get:
      tags:
        - Users
      summary: 'List forwards for a user'
      operationId: getUserUserForwardsIndex
      description: |
        Returns the user user forwards index identified by the path parameter. Multi-tenant scoping
        is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440010
                        user_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        type:
                          type: string
                          example: unconditional
                        destination:
                          type: string
                          example: '+32499123456'
                        status:
                          type: boolean
                          example: true
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440010
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    type: unconditional
                    destination: '+32499123456'
                    status: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - Users
      summary: 'Create a forward for a user'
      operationId: postUserUserForwardsIndex
      description: |
        Creates a new user user forwards index. Validation rules and required fields are defined in
        the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - enabled
                - event
                - target
              properties:
                enabled:
                  type: boolean
                  description: 'Whether this forward rule is active'
                  example: true
                name:
                  type:
                    - string
                    - 'null'
                  description: 'Optional human-readable name used to identify the forward'
                  example: Mobile
                event:
                  type: string
                  enum:
                    - busy
                    - no_answer
                    - unconditional
                    - unreachable
                  description: 'When the forward should trigger'
                  example: no_answer
                target:
                  type: string
                  enum:
                    - phone_number
                    - extension
                    - voicemail
                  description: 'Where the forward routes the call'
                  example: phone_number
                target_options:
                  type: object
                  description: 'Target-type-specific configuration'
                  additionalProperties: true
                  example:
                    phone_number: '+12125550100'
                caller_identity_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Scope the forward to a specific caller identity (null = all)'
                  example: null
            example:
              enabled: true
              event: no_answer
              target: phone_number
              target_options:
                phone_number: '+12125550100'
              caller_identity_id: null
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440010
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      type:
                        type: string
                        example: unconditional
                      destination:
                        type: string
                        example: '+32499123456'
                      status:
                        type: boolean
                        example: true
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440010
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  type: unconditional
                  destination: '+32499123456'
                  status: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/forwards/{forward}':
    put:
      tags:
        - Users
      summary: 'Update a forward for a user'
      operationId: updateUserUserForwardsSpecific
      description: |
        Replaces the user user forwards specific with the fields supplied in the request body.
        Fields omitted from the body are reset to their defaults.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: forward
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the forward'
          example: 550e8400-e29b-41d4-a716-446655440010
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - enabled
              description: 'Update accepts toggling the `enabled` flag and changing the `name`; other fields are ignored.'
              properties:
                enabled:
                  type: boolean
                  example: false
                name:
                  type:
                    - string
                    - 'null'
                  description: 'Optional human-readable name used to identify the forward'
                  example: Mobile
            example:
              enabled: false
              name: Mobile
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440010
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      enabled:
                        type: boolean
                      event:
                        type: string
                        enum:
                          - busy
                          - no_answer
                          - unconditional
                          - unreachable
                      target:
                        type: string
                        enum:
                          - phone_number
                          - extension
                          - voicemail
                      target_options:
                        type: object
                        additionalProperties: true
                      caller_identity_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440010
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  enabled: false
                  event: no_answer
                  target: phone_number
                  target_options:
                    phone_number: '+12125550100'
                  caller_identity_id: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Users
      summary: 'Delete a forward for a user'
      operationId: deleteUserUserForwardsSpecific
      description: |
        Deletes the user user forwards specific. Soft-delete behaviour is model-dependent: most
        resources are recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: forward
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the forward'
          example: 550e8400-e29b-41d4-a716-446655440010
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/favorite-users':
    post:
      tags:
        - Users
      summary: 'Add a favorite user (user)'
      operationId: createUserFavoriteUser
      description: |
        Mark another user as a favorite for the given user. The favorited user must
        belong to the same PBX as the owning user, and the same favorite cannot be
        added twice. The owning user is taken from the `{user}` path segment and the
        PBX is derived server-side; neither `user_id` nor `pbx_id` may be sent in the
        body.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'Identifier of the user who owns the favorites list'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - favorite_user_id
              properties:
                favorite_user_id:
                  type: string
                  format: uuid
                  description: |
                    Identifier of the user to mark as a favorite. Must reference an
                    existing user in the same PBX and must not already be a favorite
                    of the owning user.
            example:
              favorite_user_id: 550e8400-e29b-41d4-a716-446655440001
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  user_id:
                    type: string
                    format: uuid
                  favorite_user_id:
                    type: string
                    format: uuid
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
              example:
                id: 550e8400-e29b-41d4-a716-446655440040
                user_id: 550e8400-e29b-41d4-a716-446655440000
                favorite_user_id: 550e8400-e29b-41d4-a716-446655440001
                created_at: '2024-03-01T08:29:07Z'
                updated_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/favorite-users/{favorite_user}':
    delete:
      tags:
        - Users
      summary: 'Remove a favorite user (user)'
      operationId: deleteUserFavoriteUser
      description: |
        Remove a user from the owning user's favorites list. The owning user is
        taken from the `{user}` path segment, and the `{favorite_user}` path segment
        is the identifier of the favorited user (not the favorite record id). If no
        matching favorite exists for the pair, a `404` is returned.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'Identifier of the user who owns the favorites list'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: favorite_user
          in: path
          required: true
          description: 'Identifier of the favorited user to remove'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/phone-buttons/resolved':
    get:
      tags:
        - Users
      summary: 'Get resolved phone buttons for a user'
      operationId: getUserPhoneButtonsResolved
      description: |
        Returns the user phone buttons resolved identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        position:
                          type: integer
                          example: 1
                        type:
                          type: string
                          example: speed_dial
                        value:
                          type:
                            - string
                            - 'null'
                          example: '101'
                        label:
                          type:
                            - string
                            - 'null'
                          example: 'Front Desk'
              example:
                data:
                  -
                    position: 1
                    type: speed_dial
                    value: '101'
                    label: 'Front Desk'
                  -
                    position: 2
                    type: empty
                    value: null
                    label: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/phone-buttons/resolved-detailed':
    get:
      tags:
        - Users
      summary: 'Get resolved detailed phone buttons for a user'
      operationId: getUserPhoneButtonsResolvedDetailed
      description: |
        Returns the user phone buttons resolved detailed identified by the path parameter.
        Multi-tenant scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        position:
                          type: integer
                          example: 1
                        type:
                          type: string
                          example: speed_dial
                        value:
                          type:
                            - string
                            - 'null'
                          example: '101'
                        label:
                          type:
                            - string
                            - 'null'
                          example: 'Front Desk'
                        details:
                          type:
                            - object
                            - 'null'
                          description: 'Additional resolved details for the button target'
              example:
                data:
                  -
                    position: 1
                    type: speed_dial
                    value: '101'
                    label: 'Front Desk'
                    details:
                      extension_number: '101'
                      user_name: 'Jane Smith'
                      status: available
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/phone-buttons/preview-config':
    get:
      tags:
        - Users
      summary: 'Get phone buttons preview config for a user'
      operationId: getUserPhoneButtonsPreviewConfig
      description: |
        Returns the user phone buttons preview config identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: 'Phone button preview configuration'
                    properties:
                      model:
                        type:
                          - string
                          - 'null'
                        example: 'Yealink T46S'
                      total_buttons:
                        type: integer
                        example: 27
                      buttons:
                        type: array
                        items:
                          type: object
                          properties:
                            position:
                              type: integer
                              example: 1
                            type:
                              type: string
                              example: speed_dial
                            value:
                              type:
                                - string
                                - 'null'
                              example: '101'
                            label:
                              type:
                                - string
                                - 'null'
                              example: 'Front Desk'
              example:
                data:
                  model: 'Yealink T46S'
                  total_buttons: 27
                  buttons:
                    -
                      position: 1
                      type: speed_dial
                      value: '101'
                      label: 'Front Desk'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/phone-buttons':
    get:
      tags:
        - Users
      summary: 'List phone buttons for a user'
      operationId: getUserPhoneButtonsIndex
      description: |
        Returns the user phone buttons index identified by the path parameter. Multi-tenant scoping
        is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440030
                        user_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        number:
                          type: integer
                          minimum: 1
                          example: 1
                        type:
                          type: string
                          example: speed_dial
                        value:
                          type:
                            - string
                            - 'null'
                          example: '101'
                        label:
                          type:
                            - string
                            - 'null'
                          example: 'Front Desk'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440030
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    number: 1
                    type: speed_dial
                    value: '101'
                    label: 'Front Desk'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - Users
      summary: 'Create a phone button for a user'
      operationId: postUserPhoneButtonsIndex
      description: |
        Creates a new user phone buttons index. Validation rules and required fields are defined in
        the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - number
                - type
              description: |
                Phone button position is `number` (1-based, max determined by the
                target device). The button's `type` drives which optional `target_*`
                fields are required.
              properties:
                number:
                  type: integer
                  minimum: 1
                  description: '1-based button position on the phone'
                  example: 1
                label:
                  type:
                    - string
                    - 'null'
                  description: 'Required when `type` is anything other than `none`'
                  example: 'Front Desk'
                type:
                  type: string
                  description: 'Button kind (see PhoneButton type registry for the full enum)'
                  example: speed_dial_extension
                target_user_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Target user (when applicable to the button type)'
                target_extension_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Target extension (when applicable)'
                caller_identity_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Caller identity used (when applicable)'
                phone_number:
                  type:
                    - string
                    - 'null'
                  description: 'Raw phone number to dial (for external speed dials)'
                multicast_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Tempus status (for status-toggle buttons)'
                call_flow_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                forward_type:
                  type:
                    - string
                    - 'null'
                forward_caller_identity_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                function_action:
                  type:
                    - string
                    - 'null'
                  description: 'Built-in function (e.g. `dnd`, `voicemail`)'
                contact_phone_number_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                editable:
                  type: boolean
                sync_source:
                  type: string
                  enum:
                    - manual
                    - provision
            example:
              number: 1
              type: speed_dial_extension
              label: 'Front Desk'
              target_extension_id: 550e8400-e29b-41d4-a716-446655440010
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440030
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      number:
                        type: integer
                        minimum: 1
                        example: 1
                      type:
                        type: string
                        example: speed_dial
                      value:
                        type:
                          - string
                          - 'null'
                        example: '101'
                      label:
                        type:
                          - string
                          - 'null'
                        example: 'Front Desk'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440030
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  number: 1
                  type: speed_dial
                  value: '101'
                  label: 'Front Desk'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/phone-buttons/{phoneButtonId}':
    get:
      tags:
        - Users
      summary: 'Get a phone button for a user'
      operationId: getUserPhoneButtonsSpecific
      description: |
        Returns the user phone buttons specific identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: phoneButtonId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the phone button'
          example: 550e8400-e29b-41d4-a716-446655440030
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440030
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      number:
                        type: integer
                        minimum: 1
                        example: 1
                      type:
                        type: string
                        example: speed_dial
                      value:
                        type:
                          - string
                          - 'null'
                        example: '101'
                      label:
                        type:
                          - string
                          - 'null'
                        example: 'Front Desk'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440030
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  number: 1
                  type: speed_dial
                  value: '101'
                  label: 'Front Desk'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - Users
      summary: 'Replace a phone button for a user'
      operationId: updateUserPhoneButtonsSpecific
      description: |
        Replaces the user phone buttons specific with the fields supplied in the request body.
        Fields omitted from the body are reset to their defaults.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: phoneButtonId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the phone button'
          example: 550e8400-e29b-41d4-a716-446655440030
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: 'Same shape as POST; all fields support `sometimes` for partial updates.'
              properties:
                number:
                  type: integer
                  minimum: 1
                  example: 1
                label:
                  type:
                    - string
                    - 'null'
                  example: Support
                type:
                  type: string
                  example: speed_dial_extension
                target_user_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                target_extension_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                caller_identity_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                phone_number:
                  type:
                    - string
                    - 'null'
                function_action:
                  type:
                    - string
                    - 'null'
            example:
              label: Support
              target_extension_id: 550e8400-e29b-41d4-a716-446655440011
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440030
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      number:
                        type: integer
                        minimum: 1
                        example: 1
                      type:
                        type: string
                        example: speed_dial
                      value:
                        type:
                          - string
                          - 'null'
                        example: '102'
                      label:
                        type:
                          - string
                          - 'null'
                        example: Support
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440030
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  number: 1
                  type: speed_dial
                  value: '102'
                  label: Support
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    patch:
      tags:
        - Users
      summary: 'Partially update a phone button for a user'
      operationId: patchUserPhoneButtonsSpecific
      description: |
        Partially updates the user phone buttons specific. Only the fields supplied in the request
        body are changed; others are left untouched.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: phoneButtonId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the phone button'
          example: 550e8400-e29b-41d4-a716-446655440030
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type:
                    - string
                    - 'null'
                  example: Reception
            example:
              label: Reception
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440030
                      user_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440001
                      number:
                        type: integer
                        minimum: 1
                        example: 1
                      type:
                        type: string
                        example: speed_dial
                      value:
                        type:
                          - string
                          - 'null'
                        example: '101'
                      label:
                        type:
                          - string
                          - 'null'
                        example: Reception
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440030
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  number: 1
                  type: speed_dial
                  value: '101'
                  label: Reception
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Users
      summary: 'Delete a phone button for a user'
      operationId: deleteUserPhoneButtonsSpecific
      description: |
        Deletes the user phone buttons specific. Soft-delete behaviour is model-dependent: most
        resources are recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: phoneButtonId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the phone button'
          example: 550e8400-e29b-41d4-a716-446655440030
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/user-settings':
    get:
      tags:
        - Users
      summary: 'List settings for a user'
      operationId: getUserUserSettingsIndex
      description: |
        Returns the user user settings index identified by the path parameter. Multi-tenant scoping
        is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                          example: notifications
                        settings:
                          type: string
                          description: 'JSON-encoded settings payload (string column on the user_settings table)'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    type: notifications
                    settings: '{"email":true,"push":false}'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - Users
      summary: 'Create a setting for a user'
      operationId: postUserUserSettingsIndex
      description: |
        Creates a new user user settings index. Validation rules and required fields are defined in
        the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - settings
              properties:
                type:
                  type: string
                  description: 'Setting type key'
                  example: notifications
                settings:
                  type: string
                  description: 'JSON-encoded settings payload (string column on the user_settings table)'
            example:
              type: notifications
              settings: '{"notifications":{"email":true,"push":false}}'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      type:
                        type: string
                        example: notifications
                      settings:
                        type: string
                        description: 'JSON-encoded settings payload (string column on the user_settings table)'
              example:
                data:
                  type: notifications
                  settings: '{"email":true,"push":false}'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/user-settings/{type}':
    get:
      tags:
        - Users
      summary: 'Get a setting for a user by type'
      operationId: getUserUserSettingsSpecific
      description: |
        Returns the user user settings specific identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: type
          in: path
          required: true
          schema:
            type: string
          description: 'The setting type key'
          example: notifications
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      type:
                        type: string
                        example: notifications
                      settings:
                        type: string
                        description: 'JSON-encoded settings payload (string column on the user_settings table)'
              example:
                data:
                  type: notifications
                  settings: '{\"email\":true,\"push\":false}'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - Users
      summary: 'Replace a setting for a user by type'
      operationId: updateUserUserSettingsSpecific
      description: |
        Replaces the user user settings specific with the fields supplied in the request body.
        Fields omitted from the body are reset to their defaults.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: type
          in: path
          required: true
          schema:
            type: string
          description: 'The setting type key'
          example: notifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - settings
              properties:
                settings:
                  type: string
                  description: 'JSON-encoded settings payload (string column on the user_settings table)'
            example:
              settings: '{"email_alerts":true,"sms_alerts":false,"daily_digest":"08:00"}'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      type:
                        type: string
                        example: notifications
                      settings:
                        type: string
                        description: 'JSON-encoded settings payload (string column on the user_settings table)'
              example:
                data:
                  type: notifications
                  settings: '{"email":false,"push":true}'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    patch:
      tags:
        - Users
      summary: 'Partially update a setting for a user by type'
      operationId: patchUserUserSettingsSpecific
      description: |
        Partially updates the user user settings specific. Only the fields supplied in the request
        body are changed; others are left untouched.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: type
          in: path
          required: true
          schema:
            type: string
          description: 'The setting type key'
          example: notifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                settings:
                  type: string
                  description: 'JSON-encoded settings payload (string column on the user_settings table)'
            example:
              settings: '{"daily_digest":"09:00"}'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      type:
                        type: string
                        example: notifications
                      settings:
                        type: string
                        description: 'JSON-encoded settings payload (string column on the user_settings table)'
              example:
                data:
                  type: notifications
                  settings: '{"email":false,"push":true}'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Users
      summary: 'Delete a setting for a user by type'
      operationId: deleteUserUserSettingsSpecific
      description: |
        Deletes the user user settings specific. Soft-delete behaviour is model-dependent: most
        resources are recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: type
          in: path
          required: true
          schema:
            type: string
          description: 'The setting type key'
          example: notifications
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/twinnings':
    get:
      tags:
        - Twinning
      summary: "List a user's twinnings (user)"
      operationId: listUserTwinnings
      description: |
        List the twinnings that belong to the given user. Results are paginated.

        The following Spatie QueryBuilder filters are supported (exact match):
        `filter[status]`, `filter[phone_number]`, `filter[delay]`,
        `filter[sync_source]` and `filter[type]`. Sorting is allowed on the same
        fields; prefix a field with `-` for descending order, for example
        `sort=-delay`.

        When a twinning has Fixed-Mobile Convergence (FMC) enabled together with a
        backup phone number, the response also includes a derived read-only entry
        for that backup number. The derived entry carries a generated `id` and is
        not a separately stored record.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: page
          in: query
          required: false
          description: 'Page number to fetch. Defaults to `1`.'
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to `25`, maximum `100`.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          example: 25
        -
          name: sort
          in: query
          description: |
            Field to sort by. Allowed values are `status`, `phone_number`, `delay`,
            `sync_source` and `type`. Prefix with `-` for descending order.
          schema:
            type: string
            example: '-delay'
        -
          name: 'filter[key]'
          in: query
          description: |
            </br>The filter key can be one of: `status`, `phone_number`, `delay`,
            `sync_source` or `type` (exact match). </br>The filter value can be any
            string. </br></br> It is also possible to apply multiple filters using
            the following format: filter[status]=enabled&filter[type]=mobile
          schema:
            type: string
          example: enabled
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Twinning'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    status: enabled
                    phone_number: '+12125550100'
                    delay: 5
                    sync_source: manual
                    type: mobile
                    dial_strategy: voip_and_gsm_fallback
                    fmc_enabled: false
                    backup_phone_number: null
                    created_at: '2024-03-01T08:29:07Z'
                    updated_at: '2024-03-01T08:29:07Z'
                links:
                  first: 'https://cockpit.voxbi.com/api/v1/users/550e8400-e29b-41d4-a716-446655440001/twinnings?page=1'
                  last: 'https://cockpit.voxbi.com/api/v1/users/550e8400-e29b-41d4-a716-446655440001/twinnings?page=1'
                  prev: null
                  next: null
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  links:
                    -
                      url: 'https://cockpit.voxbi.com/api/v1/users/550e8400-e29b-41d4-a716-446655440001/twinnings?page=1'
                      label: '1'
                      active: true
                  path: 'https://cockpit.voxbi.com/api/v1/users/550e8400-e29b-41d4-a716-446655440001/twinnings'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - Twinning
      summary: 'Create a twinning for a user (user)'
      operationId: createUserTwinning
      description: |
        Create a twinning for the given user. The `user_id` is taken from the path
        and the `sync_source` is always set to `manual` server-side; neither may be
        supplied in the request body.

        Whether `phone_number` is required depends on the combination of `type` and
        `dial_strategy` (for example, a `voip_only` mobile twinning does not require
        a phone number). A user may hold at most one `teams`-type twinning and at
        most one `voip_only` twinning. `backup_phone_number` is only accepted when
        `fmc_enabled` is true and the twinning is FMC-eligible (mobile type).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
                - delay
                - type
                - dial_strategy
              properties:
                status:
                  type: string
                  enum:
                    - enabled
                    - disabled
                  description: 'Whether the twinning is active.'
                  example: enabled
                phone_number:
                  type: string
                  maxLength: 24
                  description: |
                    Twinned destination phone number (E.164 preferred). Required for
                    strategies that dial a number; ignored for Teams or VoIP-only
                    configurations.
                  example: '+12125550100'
                delay:
                  type: integer
                  minimum: 0
                  description: 'Seconds to wait before the twinning leg starts ringing.'
                  example: 5
                type:
                  type: string
                  enum:
                    - mobile
                    - teams
                  description: 'Channel used to reach the twinned destination.'
                  example: mobile
                dial_strategy:
                  type: string
                  enum:
                    - gsm_only
                    - voip_only
                    - voip_and_gsm_fallback
                  description: 'How the mobile leg is dialed.'
                  example: voip_and_gsm_fallback
                fmc_enabled:
                  type: boolean
                  description: 'Whether Fixed-Mobile Convergence is enabled.'
                  example: false
                backup_phone_number:
                  type:
                    - string
                    - 'null'
                  maxLength: 24
                  description: 'Backup number used when the primary FMC leg fails. Requires fmc_enabled.'
                  example: null
            example:
              status: enabled
              phone_number: '+12125550100'
              delay: 5
              type: mobile
              dial_strategy: voip_and_gsm_fallback
              fmc_enabled: false
              backup_phone_number: null
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Twinning'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  status: enabled
                  phone_number: '+12125550100'
                  delay: 5
                  sync_source: manual
                  type: mobile
                  dial_strategy: voip_and_gsm_fallback
                  fmc_enabled: false
                  backup_phone_number: null
                  created_at: '2024-03-01T08:29:07Z'
                  updated_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/twinnings/{twinning}':
    get:
      tags:
        - Twinning
      summary: "Get a user's twinning (user)"
      operationId: getUserTwinning
      description: |
        Retrieve a single twinning belonging to the given user. A twinning that does
        not exist, or that belongs to a different user, responds with 404.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: twinning
          in: path
          required: true
          description: 'Twinning identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Twinning'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  status: enabled
                  phone_number: '+12125550100'
                  delay: 5
                  sync_source: manual
                  type: mobile
                  dial_strategy: voip_and_gsm_fallback
                  fmc_enabled: false
                  backup_phone_number: null
                  created_at: '2024-03-01T08:29:07Z'
                  updated_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - Twinning
      summary: "Update a user's twinning (user)"
      operationId: updateUserTwinning
      description: |
        Update a twinning belonging to the given user. Every field is optional; only
        the fields present in the body are changed. `user_id` and `sync_source` are
        server-managed and must not be sent.

        For twinnings whose `sync_source` is `provision`, the `phone_number`, `type`
        and `dial_strategy` fields are locked: provisioned values are preserved and
        any conflicting values are rejected.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: twinning
          in: path
          required: true
          description: 'Twinning identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum:
                    - enabled
                    - disabled
                phone_number:
                  type: string
                  maxLength: 24
                delay:
                  type: integer
                  minimum: 0
                type:
                  type: string
                  enum:
                    - mobile
                    - teams
                dial_strategy:
                  type: string
                  enum:
                    - gsm_only
                    - voip_only
                    - voip_and_gsm_fallback
                fmc_enabled:
                  type: boolean
                backup_phone_number:
                  type:
                    - string
                    - 'null'
                  maxLength: 24
            example:
              status: disabled
              delay: 10
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Twinning'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  status: disabled
                  phone_number: '+12125550100'
                  delay: 10
                  sync_source: manual
                  type: mobile
                  dial_strategy: voip_and_gsm_fallback
                  fmc_enabled: false
                  backup_phone_number: null
                  created_at: '2024-03-01T08:29:07Z'
                  updated_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    patch:
      tags:
        - Twinning
      summary: "Update a user's twinning (user)"
      operationId: patchUserTwinning
      description: |
        Alias of the `PUT` update with identical request shape and validation rules.
        Only the fields present in the body are changed; `user_id` and `sync_source`
        are server-managed. Provisioned twinnings keep their locked
        `phone_number`, `type` and `dial_strategy` values.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: twinning
          in: path
          required: true
          description: 'Twinning identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum:
                    - enabled
                    - disabled
                phone_number:
                  type: string
                  maxLength: 24
                delay:
                  type: integer
                  minimum: 0
                type:
                  type: string
                  enum:
                    - mobile
                    - teams
                dial_strategy:
                  type: string
                  enum:
                    - gsm_only
                    - voip_only
                    - voip_and_gsm_fallback
                fmc_enabled:
                  type: boolean
                backup_phone_number:
                  type:
                    - string
                    - 'null'
                  maxLength: 24
            example:
              status: enabled
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Twinning'
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  user_id: 550e8400-e29b-41d4-a716-446655440001
                  status: enabled
                  phone_number: '+12125550100'
                  delay: 5
                  sync_source: manual
                  type: mobile
                  dial_strategy: voip_and_gsm_fallback
                  fmc_enabled: false
                  backup_phone_number: null
                  created_at: '2024-03-01T08:29:07Z'
                  updated_at: '2024-03-01T08:29:07Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Twinning
      summary: "Delete a user's twinning (user)"
      operationId: deleteUserTwinning
      description: |
        Delete a twinning belonging to the given user. A twinning whose
        `sync_source` is `provision` cannot be removed through this endpoint and
        responds with 422.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          description: 'User identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: twinning
          in: path
          required: true
          description: 'Twinning identifier'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/user-groups':
    get:
      tags:
        - Users
      summary: 'List user-groups for a user'
      operationId: getUserUserUserGroupsIndex
      description: |
        Returns the user user user groups index identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440020
                        name:
                          type: string
                          example: 'Sales Team'
                        position:
                          type: integer
                          example: 1
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440020
                    name: 'Sales Team'
                    position: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    post:
      tags:
        - Users
      summary: 'Add a user-group to a user'
      operationId: postUserUserUserGroupsIndex
      description: |
        Creates a new user user user groups index. Validation rules and required fields are defined
        in the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                user_group_id:
                  type: string
                  format: uuid
                  example: 550e8400-e29b-41d4-a716-446655440020
                position:
                  type: integer
                  example: 1
            example:
              user_group_id: 550e8400-e29b-41d4-a716-446655440020
              position: 1
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440020
                      name:
                        type: string
                        example: 'Sales Team'
                      position:
                        type: integer
                        example: 1
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440020
                  name: 'Sales Team'
                  position: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/users/{user}/user-groups/{userGroup}':
    get:
      tags:
        - Users
      summary: 'Get a user-group for a user'
      operationId: getUserUserUserGroupsSpecific
      description: |
        Returns the user user user groups specific identified by the path parameter. Multi-tenant
        scoping is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: userGroup
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440020
                      name:
                        type: string
                        example: 'Sales Team'
                      position:
                        type: integer
                        example: 1
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440020
                  name: 'Sales Team'
                  position: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    patch:
      tags:
        - Users
      summary: 'Partially update a user-group for a user'
      operationId: updateUserUserUserGroupsSpecific
      description: |
        Partially updates the user user user groups specific. Only the fields supplied in the
        request body are changed; others are left untouched.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: userGroup
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                position:
                  type: integer
                  example: 2
            example:
              position: 2
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440020
                      name:
                        type: string
                        example: 'Sales Team'
                      position:
                        type: integer
                        example: 2
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440020
                  name: 'Sales Team'
                  position: 2
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - Users
      summary: 'Remove a user-group from a user'
      operationId: deleteUserUserUserGroupsSpecific
      description: |
        Deletes the user user user groups specific. Soft-delete behaviour is model-dependent: most
        resources are recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: userGroup
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'Deleted (no content)'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/users/{user}/right-to-disconnect':
    get:
      tags:
        - Users
      summary: 'Get right-to-disconnect settings for a user'
      operationId: getUserRightToDisconnect
      description: |
        Returns the user right to disconnect identified by the path parameter. Multi-tenant scoping
        is enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      enabled:
                        type: boolean
                        example: true
                      schedule:
                        type:
                          - object
                          - 'null'
                        description: 'Right-to-disconnect schedule configuration'
              example:
                data:
                  enabled: true
                  schedule:
                    weekdays:
                      start: '18:00'
                      end: '08:00'
                    weekend: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - Users
      summary: 'Update right-to-disconnect settings for a user'
      operationId: updateUserRightToDisconnect
      description: |
        Replaces the user right to disconnect with the fields supplied in the request body. Fields
        omitted from the body are reset to their defaults.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: user
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled:
                  type: boolean
                  example: true
                schedule:
                  type:
                    - object
                    - 'null'
                  description: 'Right-to-disconnect schedule configuration'
            example:
              enabled: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      enabled:
                        type: boolean
                        example: true
                      schedule:
                        type:
                          - object
                          - 'null'
              example:
                data:
                  enabled: true
                  schedule:
                    weekdays:
                      start: '18:00'
                      end: '08:00'
                    weekend: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /user-groups:
    get:
      tags:
        - UserGroups
      summary: 'List user groups'
      operationId: listUserGroups
      description: |
        Returns a paginated list of user groups. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440020
                        name:
                          type: string
                          example: 'Sales Team'
                        user_id:
                          type: string
                          format: uuid
                          description: 'Owner user (a user-group belongs to one user)'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        position:
                          type: integer
                          example: 1
                        users:
                          type: array
                          description: 'Member user identifiers (when included)'
                          items:
                            type: string
                            format: uuid
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440020
                    name: 'Sales Team'
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    position: 1
                  -
                    id: 550e8400-e29b-41d4-a716-446655440021
                    name: 'Support Team'
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    position: 2
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
    post:
      tags:
        - UserGroups
      summary: 'Create a user-group'
      operationId: createUserGroup
      description: |
        Creates a new user group. Validation rules and required fields are defined in the request
        body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - user_ids
              properties:
                name:
                  type: string
                  example: 'Sales Team'
                user_ids:
                  type: array
                  description: 'UUIDs of users to add to this group (must belong to the same PBX as the authenticated user)'
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
            example:
              name: 'Sales Team'
              user_ids:
                - 550e8400-e29b-41d4-a716-446655440010
                - 550e8400-e29b-41d4-a716-446655440011
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      created_entry:
                        type: object
                        description: 'The newly-created user-group resource'
                        properties:
                          id:
                            type: string
                            format: uuid
                          name:
                            type: string
                          user_id:
                            type: string
                            format: uuid
                          users:
                            type: array
                            items:
                              type: string
                              format: uuid
                      non_added_user_ids:
                        type: array
                        description: 'User IDs that were not added (e.g. wrong PBX)'
                        items:
                          type: string
                          format: uuid
              example:
                success: true
                message: 'User group created successfully'
                data:
                  created_entry:
                    id: 550e8400-e29b-41d4-a716-446655440020
                    name: 'Sales Team'
                    user_id: 550e8400-e29b-41d4-a716-446655440001
                    users:
                      - 550e8400-e29b-41d4-a716-446655440010
                      - 550e8400-e29b-41d4-a716-446655440011
                  non_added_user_ids: {}
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /user-groups/update-positions:
    post:
      tags:
        - UserGroups
      summary: 'Update positions of user-groups'
      operationId: postUserGroupUpdatePositions
      description: |
        Creates a new user group update positions. Validation rules and required fields are defined
        in the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                required:
                  - id
                  - position
                properties:
                  id:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440020
                  position:
                    type: integer
                    example: 1
            example:
              -
                id: 550e8400-e29b-41d4-a716-446655440020
                position: 1
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Positions updated successfully'
              example:
                message: 'Positions updated successfully'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/user-groups/{userGroupId}':
    get:
      tags:
        - UserGroups
      summary: 'Get an user-group'
      operationId: getUserGroup
      description: |
        Returns the user group identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440020
                      name:
                        type: string
                        example: 'Sales Team'
                      position:
                        type: integer
                        example: 1
                      pbx_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440000
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440020
                  name: 'Sales Team'
                  position: 1
                  pbx_id: 550e8400-e29b-41d4-a716-446655440000
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    patch:
      tags:
        - UserGroups
      summary: 'Partially update a user-group'
      operationId: updateUserGroup
      description: |
        Partially updates the user group. Only the fields supplied in the request body are changed;
        others are left untouched.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - user_ids
              properties:
                name:
                  type: string
                  example: 'Sales Team Updated'
                user_ids:
                  type: array
                  description: 'Full replacement set of member user IDs'
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
                position:
                  type: integer
                  example: 2
            example:
              name: 'Sales Team Updated'
              user_ids:
                - 550e8400-e29b-41d4-a716-446655440010
                - 550e8400-e29b-41d4-a716-446655440011
              position: 2
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440020
                      name:
                        type: string
                        example: 'Sales Team Updated'
                      position:
                        type: integer
                        example: 2
                      pbx_id:
                        type: string
                        format: uuid
                        example: 550e8400-e29b-41d4-a716-446655440000
              example:
                data:
                  id: 550e8400-e29b-41d4-a716-446655440020
                  name: 'Sales Team Updated'
                  position: 2
                  pbx_id: 550e8400-e29b-41d4-a716-446655440000
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - UserGroups
      summary: 'Delete a user-group'
      operationId: deleteUserGroup
      description: |
        Deletes the user group. Soft-delete behaviour is model-dependent: most resources are
        recoverable via the restore endpoint, while a few are hard-deleted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User-group deleted successfully'
              example:
                message: 'User-group deleted successfully'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/user-groups/{userGroupId}/add-users':
    post:
      tags:
        - UserGroups
      summary: 'Add users to a user-group'
      operationId: postUserGroupAddUsers
      description: |
        Creates a new user group add users. Validation rules and required fields are defined in the
        request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_ids
              properties:
                user_ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440001
                    - 550e8400-e29b-41d4-a716-446655440002
            example:
              user_ids:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Users added successfully'
              example:
                message: 'Users added successfully'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/user-groups/{userGroupId}/remove-users':
    post:
      tags:
        - UserGroups
      summary: 'Remove users from a user-group'
      operationId: postUserGroupRemoveUsers
      description: |
        Creates a new user group remove users. Validation rules and required fields are defined in
        the request body schema below.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the user-group'
          example: 550e8400-e29b-41d4-a716-446655440020
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_ids
              properties:
                user_ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440001
                    - 550e8400-e29b-41d4-a716-446655440002
            example:
              user_ids:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Users removed successfully'
              example:
                message: 'Users removed successfully'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/pools/{id}/users':
    get:
      tags:
        - Pools
      summary: 'List users in a pool'
      operationId: getPoolUsers
      description: |
        Returns the pool users identified by the path parameter. Multi-tenant scoping is enforced:
        the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the pool'
          example: 550e8400-e29b-41d4-a716-446655440050
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440001
                        first_name:
                          type: string
                          example: John
                        last_name:
                          type: string
                          example: Doe
                        email:
                          type: string
                          example: john.doe@example.com
                        status:
                          type: string
                          example: enabled
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440001
                    first_name: John
                    last_name: Doe
                    email: john.doe@example.com
                    status: enabled
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /voxbi-group-tabs:
    get:
      tags:
        - VoxbiGroupTabs
      summary: 'List all voxbi group tabs'
      operationId: listVoxbiGroupTabs
      description: |
        Returns a paginated list of voxbi group tabs. Use the standard `search`, `sort`, `page`, and
        `perPage` query parameters; use `filter[key]=value` to narrow the result set. Multi-tenant
        scoping is enforced.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        A Voxbi group tab as it appears in the authenticated user's Voxbi interface.
                        Each tab is backed by a `Group` and surfaces the set of fellow members the
                        caller can monitor and interact with. The `users` array lists only the user
                        identifiers that are relevant for the current caller: members that have at
                        least one extension assigned, with the authenticated user themselves excluded
                        (a user never appears in their own tab).
                      required:
                        - id
                        - pbx_id
                        - name
                        - description
                        - users
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique identifier of the underlying group that backs this tab.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                          readOnly: true
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'Identifier of the Pbx (tenant) that owns this group.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        name:
                          type: string
                          description: 'Display name of the group shown as the tab label.'
                          example: 'Sales Team'
                        description:
                          type:
                            - string
                            - 'null'
                          description: 'Optional free-form description of the group.'
                          example: 'All sales representatives'
                        users:
                          type: array
                          description: |
                            Identifiers of the group members that are visible to the authenticated
                            caller in this tab. The list is filtered to members that have at least
                            one extension assigned, and the authenticated user's own identifier is
                            always excluded. May be empty when no other eligible members exist.
                          items:
                            type: string
                            format: uuid
                            description: 'Identifier of a fellow group member with an assigned extension.'
                            example: 550e8400-e29b-41d4-a716-446655440002
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440060
                    pbx_id: 550e8400-e29b-41d4-a716-446655440000
                    name: 'Sales Team'
                    description: 'All sales representatives'
                    users:
                      - 550e8400-e29b-41d4-a716-446655440002
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /change-status:
    post:
      tags:
        - Users
      summary: 'Change presence status for the authenticated user (user)'
      operationId: changeUserStatus
      description: |
        Record a presence status change for the authenticated user. This opens a new
        timepoint for the selected status and, when the status is mapped to the
        external Tempus system, propagates the change and returns the updated
        work-time totals.

        `status_id` accepts either a Cockpit status UUID or an external Tempus mapping
        identifier, which is resolved to the matching Cockpit status server-side. The
        user and PBX are always derived from the authenticated token and must not be
        sent in the request body.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status_id
              properties:
                status_id:
                  type: string
                  description: |
                    Target status. A Cockpit status UUID, or an external Tempus
                    mapping identifier that is resolved server-side.
                  example: 550e8400-e29b-41d4-a716-446655440000
                location_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Optional location to associate with the status. Must reference a
                    location enabled for presence status.
                  example: 550e8400-e29b-41d4-a716-446655440010
                sub_status_ids:
                  type:
                    - array
                    - 'null'
                  description: |
                    Optional sub-status identifiers linked to the selected status.
                    A single value unless the status allows multiselect; required
                    when the status mandates a sub-status selection.
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440020
                sources:
                  type:
                    - array
                    - 'null'
                  description: 'Origin channels for the status change.'
                  items:
                    type: string
                  example:
                    - mobile
                triggers:
                  type:
                    - array
                    - 'null'
                  description: 'Triggers that initiated the status change.'
                  items:
                    type: string
                  example:
                    - manual
                meta_data:
                  type:
                    - object
                    - 'null'
                  additionalProperties: true
                  description: |
                    Arbitrary metadata, stored verbatim on the time point.

                    GPS coordinates may be sent here (as `lat`/`lng`,
                    `latitude`/`longitude`, or `gpsLat`/`gpsLong`, with an optional
                    `accuracy` and `gpsTimestamp`) or in `gpsData`. Either way the
                    server normalises them onto the time point as `device_gps` and
                    compares them with the selected `location_id`, exposing the
                    result as `location_check`. See the `TempusTimePoint` model.

                    Coordinates sent here are recorded as-is. They are never
                    replaced by the coordinates configured on `location_id`, which
                    is what makes a `location_id` that disagrees with the device's
                    position detectable afterwards.
                  example:
                    lat: 49.6116
                    lng: 6.1319
                gpsData:
                  type:
                    - object
                    - 'null'
                  additionalProperties: true
                  description: |
                    The device's GPS fix, as clients have historically sent it. An
                    alternative container for the coordinates described under
                    `meta_data`: both are accepted, both are stored, and sending
                    both no longer discards this one. Also forwarded to the
                    downstream Tempus webhook.

                    Values are read tolerantly. A fix that is unusable (only one of
                    the pair, non-numeric, or out of range) does not fail the
                    request: it is stored as sent, and `location_check.reason`
                    reports `no_device_gps`.
                  example:
                    gpsLat: 49.6116
                    gpsLong: 6.1319
                    accuracy: 12.5
                    gpsTimestamp: 1783418859289
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional free-text comment.'
                  example: 'Starting morning shift'
            example:
              status_id: 550e8400-e29b-41d4-a716-446655440000
              location_id: 550e8400-e29b-41d4-a716-446655440010
              sub_status_ids:
                - 550e8400-e29b-41d4-a716-446655440020
              sources:
                - mobile
              triggers:
                - manual
              meta_data:
                app_version: 3.4.1
              gpsData:
                gpsLat: 49.6116
                gpsLong: 6.1319
                accuracy: 12.5
                gpsTimestamp: 1783418859289
              comment: 'Starting morning shift'
      responses:
        200:
          description: |
            Status change processed without opening a new time point: either the
            submit collapsed onto the already-open time point (same status and same
            `location_id` inside the same clock minute), or the status carries no
            Tempus mapping id so nothing was synced downstream. In the latter case
            `ui.data` is an empty array.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ui:
                    type: object
                    properties:
                      data:
                        oneOf:
                          -
                            $ref: '#/components/schemas/TempusTimePoint'
                          -
                            type: array
                            maxItems: 0
                            items:
                              type: object
                  workTimes:
                    type: object
                    additionalProperties: true
                  message:
                    type:
                      - string
                      - 'null'
              example:
                ui:
                  data: {}
                workTimes:
                  daily: '08:00:00'
                  weekly: '40:00:00'
                message: 'Status applied'
        201:
          description: |
            A new time point was opened. `ui.data` is the created time point,
            including `device_gps` (the coordinates the client sent, stored as sent)
            and `location_check` (how they compare with the selected location's
            geofence).
          content:
            application/json:
              schema:
                type: object
                properties:
                  ui:
                    type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/TempusTimePoint'
                  workTimes:
                    type: object
                    additionalProperties: true
              example:
                ui:
                  data:
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    user_id: 550e8400-e29b-41d4-a716-446655440002
                    status_id: 550e8400-e29b-41d4-a716-446655440003
                    location_id: 550e8400-e29b-41d4-a716-446655440010
                    start_time: '2026-07-07T10:07:39.000000Z'
                    end_time: null
                    sources:
                      - mobile
                    triggers:
                      - manual
                    meta_data:
                      app_version: 3.4.1
                      gpsLat: 49.95
                      gpsLong: 6.133
                      source: api_v1
                      device_gps:
                        latitude: 49.95
                        longitude: 6.133
                        accuracy_m: 12.5
                        captured_at: '2026-07-07T10:07:39+00:00'
                        captured_at_raw: 1783418859289
                      location_check:
                        location_id: 550e8400-e29b-41d4-a716-446655440010
                        location_latitude: 49.6008
                        location_longitude: 6.133
                        geofence_radius_m: 150
                        distance_m: 38957
                        within_geofence: false
                        verdict: mismatch
                        reason: null
                    is_synced: false
                    location:
                      id: 550e8400-e29b-41d4-a716-446655440010
                      name: 'HQ Luxembourg'
                      latitude: 49.6008
                      longitude: 6.133
                      geofence_radius_m: 150
                      is_fixed_location: true
                    device_gps:
                      latitude: 49.95
                      longitude: 6.133
                      accuracy_m: 12.5
                      captured_at: '2026-07-07T10:07:39+00:00'
                      captured_at_raw: 1783418859289
                    location_check:
                      location_id: 550e8400-e29b-41d4-a716-446655440010
                      location_latitude: 49.6008
                      location_longitude: 6.133
                      geofence_radius_m: 150
                      distance_m: 38957
                      within_geofence: false
                      verdict: mismatch
                      reason: null
                    created_at: '2026-07-07T10:07:39.000000Z'
                    updated_at: '2026-07-07T10:07:39.000000Z'
                workTimes:
                  daily: '08:00:00'
                  weekly: '40:00:00'
        409:
          description: |
            Another status change for this employee is already in progress and could
            not be resolved. Retry once after a short delay.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: 'null'
                  errors:
                    type: array
                    items:
                      type: string
                  message:
                    type: string
              example:
                data: null
                errors:
                  - 'Another status change is already in progress. Please try again.'
                message: 'Status change failed.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /timepoints:
    get:
      tags:
        - Users
      summary: 'List presence timepoints for the authenticated user (user)'
      operationId: listUserTimepoints
      description: |
        Return a paginated list of presence timepoints (status changes recorded over
        time) scoped to the authenticated user's PBX. Results are sorted by
        `start_time` descending by default.

        Filtering and sorting follow the Spatie query-builder convention: filters are
        passed as `filter[<field>]` and sorts as a comma-separated `sort` value where
        a leading `-` denotes descending order.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page. Defaults to 50.'
          schema:
            type: integer
            default: 50
            example: 50
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            example: 1
        -
          name: 'filter[user_id]'
          in: query
          required: false
          description: 'Filter by user identifier.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[status_id]'
          in: query
          required: false
          description: 'Filter by status identifier.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[start_time]'
          in: query
          required: false
          description: 'Filter by start time.'
          schema:
            type: string
            format: date-time
            example: '2024-03-01T08:00:00Z'
        -
          name: 'filter[end_time]'
          in: query
          required: false
          description: 'Filter by end time.'
          schema:
            type: string
            format: date-time
            example: '2024-03-01T17:00:00Z'
        -
          name: 'filter[is_synced]'
          in: query
          required: false
          description: 'Filter by sync state with the external Tempus system.'
          schema:
            type: boolean
            example: true
        -
          name: sort
          in: query
          required: false
          description: |
            Sort field. Allowed values: `start_time`, `end_time`, `created_at`.
            Prefix with `-` for descending order. Defaults to `-start_time`.
          schema:
            type: string
            example: '-start_time'
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTimePoint'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440000
                    pbx_id: 550e8400-e29b-41d4-a716-446655440001
                    user_id: 550e8400-e29b-41d4-a716-446655440002
                    status_id: 550e8400-e29b-41d4-a716-446655440003
                    location_id: 550e8400-e29b-41d4-a716-446655440010
                    start_time: '2026-07-07T10:07:39Z'
                    end_time: '2026-07-07T12:00:00Z'
                    sources:
                      - mobile
                    triggers:
                      - manual
                    meta_data:
                      gpsLat: 49.95
                      gpsLong: 6.133
                      source: api_v1
                      device_gps:
                        latitude: 49.95
                        longitude: 6.133
                        accuracy_m: 12.5
                        captured_at: '2026-07-07T10:07:39+00:00'
                        captured_at_raw: 1783418859289
                      location_check:
                        location_id: 550e8400-e29b-41d4-a716-446655440010
                        location_latitude: 49.6008
                        location_longitude: 6.133
                        geofence_radius_m: 150
                        distance_m: 38957
                        within_geofence: false
                        verdict: mismatch
                        reason: null
                    location:
                      id: 550e8400-e29b-41d4-a716-446655440010
                      name: 'HQ Luxembourg'
                      latitude: 49.6008
                      longitude: 6.133
                      geofence_radius_m: 150
                      is_fixed_location: true
                    device_gps:
                      latitude: 49.95
                      longitude: 6.133
                      accuracy_m: 12.5
                      captured_at: '2026-07-07T10:07:39+00:00'
                      captured_at_raw: 1783418859289
                    location_check:
                      location_id: 550e8400-e29b-41d4-a716-446655440010
                      location_latitude: 49.6008
                      location_longitude: 6.133
                      geofence_radius_m: 150
                      distance_m: 38957
                      within_geofence: false
                      verdict: mismatch
                      reason: null
                    is_synced: true
                    created_at: '2026-07-07T10:07:39Z'
                    updated_at: '2026-07-07T12:00:00Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /workTimes:
    get:
      tags:
        - Users
      summary: 'Get accumulated work times for the authenticated user (user)'
      operationId: getUserWorkTimes
      description: |
        Return the accumulated work-time totals for the authenticated user. When the
        PBX's Tempus app is sourced from Cockpit the totals are calculated locally;
        otherwise they are fetched from the external Tempus system. If no data is
        available, zeroed totals are returned.

        All durations are formatted as `HH:MM:SS` strings. `min*` values represent the
        minimum (contractually required) duration for the corresponding period.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  workTimes:
                    type: object
                    properties:
                      daily:
                        type: string
                        example: '08:00:00'
                      minDaily:
                        type: string
                        example: '08:00:00'
                      weekly:
                        type: string
                        example: '40:00:00'
                      minWeekly:
                        type: string
                        example: '40:00:00'
                      monthly:
                        type: string
                        example: '160:00:00'
                      minMonthly:
                        type: string
                        example: '160:00:00'
                      lunch:
                        type: string
                        example: '01:00:00'
              example:
                workTimes:
                  daily: '08:00:00'
                  minDaily: '08:00:00'
                  weekly: '40:00:00'
                  minWeekly: '40:00:00'
                  monthly: '160:00:00'
                  minMonthly: '160:00:00'
                  lunch: '01:00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /webhooks/famulor/post-call:
    post:
      tags:
        - Webhooks
      summary: 'Receive Famulor post-call events'
      operationId: postWebhookFamulor
      description: 'Receives post-call payload from Famulor AI voice assistant after a call completes. Optionally validates the request via the X-Webhook-Secret header.'
      security: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
        -
          name: X-Webhook-Secret
          in: header
          required: false
          schema:
            type: string
          description: 'Optional webhook secret for request validation.'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: 'Famulor post-call payload. The structure is defined by Famulor and may vary.'
              properties:
                assistant_id:
                  type: string
                  description: 'The Famulor assistant (agent) ID.'
                call_id:
                  type: string
                  description: 'Unique identifier for the call.'
                id:
                  type: string
                  description: 'Alternative call identifier field.'
                status:
                  type: string
                  description: 'Status of the call (e.g. completed, missed).'
                type:
                  type: string
                  description: 'Type of call.'
                client_phone_number:
                  type: string
                  description: 'Phone number of the client.'
                assistant_phone_number:
                  type: string
                  description: 'Phone number of the assistant.'
                answered_by:
                  type:
                    - string
                    - 'null'
                  description: 'Who answered the call.'
                created_at:
                  type: string
                  format: date-time
                  description: 'Timestamp when the call was initiated.'
                duration:
                  type: integer
                  description: 'Call duration in seconds.'
                total_cost:
                  type: number
                  description: 'Total cost of the call.'
                carrier_cost:
                  type: number
                  description: 'Carrier cost portion of the total.'
                transcript:
                  type:
                    - string
                    - 'null'
                  description: 'Full transcript of the call.'
                variables:
                  type:
                    - object
                    - 'null'
                  description: 'Custom variables associated with the call.'
                evaluation:
                  type:
                    - object
                    - 'null'
                  description: 'Post-call evaluation data.'
                recording_url:
                  type:
                    - string
                    - 'null'
                  description: 'URL of the call recording.'
              additionalProperties: true
            example:
              assistant_id: asst_abc123
              call_id: call_xyz789
              status: completed
              type: inbound
              client_phone_number: '+32477123456'
              assistant_phone_number: '+32489654321'
              answered_by: assistant
              created_at: '2023-10-12T12:00:00Z'
              duration: 120
              total_cost: 0.05
              carrier_cost: 0.02
              transcript: 'Hello, how can I help you today?'
              variables: null
              evaluation: null
              recording_url: 'https://storage.famulor.com/recordings/call_xyz789.mp3'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
              example:
                success: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /v2/test-latency:
    get:
      tags:
        - v2
      summary: 'Test API Latency'
      operationId: getV2TestLatency
      description: 'A lightweight endpoint with no processing logic, used to measure API round-trip latency.'
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      servers:
        -
          url: 'https://cockpit.voxbi.com/api'
          description: 'v2 API server'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  timestamp:
                    type: string
                    format: date-time
              example:
                message: 'Test endpoint - no processing'
                timestamp: '2023-10-12T12:25:52.000000Z'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /v2/change-status:
    post:
      tags:
        - v2
      summary: 'Change User Status'
      operationId: postV2ChangeStatus
      description: "Changes the authenticated user's status in the Tempus time-attendance system. Accepts either a Cockpit UUID or a Tempus mapping ID for the status."
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      servers:
        -
          url: 'https://cockpit.voxbi.com/api'
          description: 'v2 API server'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - status_id
              properties:
                status_id:
                  type: string
                  description: 'The status UUID (Cockpit) or mapping ID (Tempus). If not a UUID, the system will attempt to resolve it via the Tempus mapping.'
                location_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Optional location to associate with the status. Must reference a
                    location of the caller's own PBX that is enabled for presence
                    status.
                sub_status_ids:
                  type:
                    - array
                    - 'null'
                  description: |
                    Sub-status identifiers linked to the selected status. A single
                    value unless the status allows multiselect; required when the
                    status mandates a sub-status selection.
                  items:
                    type: string
                    format: uuid
                sources:
                  type:
                    - array
                    - 'null'
                  items:
                    type: string
                  description: 'Origin channels for the status change.'
                triggers:
                  type:
                    - array
                    - 'null'
                  items:
                    type: string
                  description: 'Triggers that initiated the status change.'
                meta_data:
                  type:
                    - object
                    - 'null'
                  additionalProperties: true
                  description: |
                    Arbitrary metadata, stored verbatim on the time point. GPS
                    coordinates may be sent here (as `lat`/`lng`,
                    `latitude`/`longitude`, or `gpsLat`/`gpsLong`) or in `gpsData`.
                    Either way they are normalised onto the time point as
                    `device_gps` and compared with `location_id`, with the result
                    exposed as `location_check`.

                    Coordinates are recorded as sent and are never replaced by the
                    coordinates configured on `location_id`.
                gpsData:
                  type:
                    - object
                    - 'null'
                  additionalProperties: true
                  description: |
                    The device's GPS fix, as clients have historically sent it. An
                    alternative container to `meta_data`: both are accepted, both
                    are stored, and sending both no longer discards this one.

                    Read tolerantly. An unusable fix (half a pair, non-numeric, or
                    out of range) does not fail the request: it is stored as sent
                    and `location_check.reason` reports `no_device_gps`.
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional free-text comment.'
            example:
              status_id: 550e8400-e29b-41d4-a716-446655440001
              location_id: 550e8400-e29b-41d4-a716-446655440010
              sub_status_ids:
                - 550e8400-e29b-41d4-a716-446655440020
              sources:
                - mobile
              triggers:
                - manual
              meta_data:
                app_version: 3.4.1
              gpsData:
                gpsLat: 49.95
                gpsLong: 6.133
                accuracy: 12.5
                gpsTimestamp: 1783418859289
              comment: 'Starting morning shift'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  ui:
                    type: object
                    properties:
                      data:
                        oneOf:
                          -
                            $ref: '#/components/schemas/TempusTimePoint'
                          -
                            type: array
                            maxItems: 0
                            items:
                              type: object
                  workTimes:
                    type:
                      - object
                      - 'null'
                    description: 'Always null on v2; poll the work-times endpoint instead.'
                  message:
                    type: string
              example:
                ui:
                  data: {}
                workTimes: null
                message: 'Status changed successfully.'
        201:
          description: |
            A new time point was opened. `ui.data` is the created time point,
            including `device_gps` (the coordinates the client sent, stored as sent)
            and `location_check` (how they compare with the selected location's
            configured coordinates and geofence radius).
          content:
            application/json:
              schema:
                type: object
                properties:
                  ui:
                    type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/TempusTimePoint'
                  workTimes:
                    type: 'null'
              example:
                ui:
                  data:
                    id: 550e8400-e29b-41d4-a716-446655440000
                    status_id: 550e8400-e29b-41d4-a716-446655440003
                    location_id: 550e8400-e29b-41d4-a716-446655440010
                    start_time: '2026-07-07T10:07:39.000000Z'
                    end_time: null
                    device_gps:
                      latitude: 49.95
                      longitude: 6.133
                      accuracy_m: 12.5
                      captured_at: '2026-07-07T10:07:39+00:00'
                      captured_at_raw: 1783418859289
                    location_check:
                      location_id: 550e8400-e29b-41d4-a716-446655440010
                      location_latitude: 49.6008
                      location_longitude: 6.133
                      geofence_radius_m: 150
                      distance_m: 38957
                      within_geofence: false
                      verdict: mismatch
                      reason: null
                workTimes: null
        409:
          description: |
            Another status change for this employee is already in progress and could
            not be resolved. Retry once after a short delay.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: 'null'
                  errors:
                    type: array
                    items:
                      type: string
                  message:
                    type: string
              example:
                data: null
                errors:
                  - 'Another status change is already in progress. Please try again.'
                message: 'Status change failed.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /v2/layout:
    get:
      tags:
        - v2
      summary: 'Get User Layout'
      operationId: getV2Layout
      description: 'Returns the active status-changer layout for the authenticated user, including grid configuration, statuses, and substatuses.'
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      servers:
        -
          url: 'https://cockpit.voxbi.com/api'
          description: 'v2 API server'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                  grid_size:
                    type: object
                    properties:
                      rows:
                        type: integer
                      columns:
                        type: integer
                  statuses:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                        description:
                          type:
                            - string
                            - 'null'
                        style:
                          type: object
                        metadata:
                          type: object
                          properties:
                            availability:
                              type:
                                - string
                                - 'null'
                            allow_multiselect:
                              type: boolean
                            substatus_selection_mandatory:
                              type: boolean
                        location_ids:
                          type: array
                          items:
                            type: string
                        substatus_ids:
                          type: array
                          items:
                            type: string
                        css_grid_area:
                          type: string
                        position:
                          type: object
                          properties:
                            row:
                              type: integer
                            column:
                              type: integer
                            row_span:
                              type: integer
                            col_span:
                              type: integer
                  substatuses:
                    type: object
                    additionalProperties:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                        description:
                          type:
                            - string
                            - 'null'
                        style:
                          type: object
              example:
                id: 550e8400-e29b-41d4-a716-446655440010
                name: 'Default Layout'
                grid_size:
                  rows: 3
                  columns: 4
                statuses:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440001
                    name: Available
                    description: null
                    style:
                      background_color: '#00c853'
                      font_color: '#ffffff'
                      icon: check
                    metadata:
                      availability: available
                      allow_multiselect: false
                      substatus_selection_mandatory: false
                    location_ids: {}
                    substatus_ids: {}
                    css_grid_area: 1/1/2/2
                    position:
                      row: 1
                      column: 1
                      row_span: 1
                      col_span: 1
                substatuses: {}
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  /v2/statuses:
    get:
      tags:
        - v2
      summary: 'Get v2 Statuses'
      operationId: getV2Statuses
      description: "Returns all Tempus statuses available for the authenticated user's PBX tenant, including style, metadata, and associated substatus and location IDs."
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      servers:
        -
          url: 'https://cockpit.voxbi.com/api'
          description: 'v2 API server'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                    name:
                      type: string
                    description:
                      type:
                        - string
                        - 'null'
                    style:
                      type: object
                      description: 'Display style properties such as colors and icon.'
                    metadata:
                      type: object
                      properties:
                        availability:
                          type:
                            - string
                            - 'null'
                        allow_multiselect:
                          type: boolean
                        substatus_selection_mandatory:
                          type: boolean
                    location_ids:
                      type: array
                      items:
                        type: string
                        format: uuid
                    substatus_ids:
                      type: array
                      items:
                        type: string
                        format: uuid
              example:
                -
                  id: 550e8400-e29b-41d4-a716-446655440001
                  name: Available
                  description: null
                  style:
                    background_color: '#00c853'
                    font_color: '#ffffff'
                    icon: check
                  metadata:
                    availability: available
                    allow_multiselect: false
                    substatus_selection_mandatory: false
                  location_ids: {}
                  substatus_ids: {}
                -
                  id: 550e8400-e29b-41d4-a716-446655440002
                  name: Busy
                  description: null
                  style:
                    background_color: '#d32f2f'
                    font_color: '#ffffff'
                    icon: phone
                  metadata:
                    availability: busy
                    allow_multiselect: false
                    substatus_selection_mandatory: true
                  location_ids: {}
                  substatus_ids:
                    - 660e8400-e29b-41d4-a716-446655440001
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /v2/substatuses:
    get:
      tags:
        - v2
      summary: 'Get v2 Substatuses'
      operationId: getV2Substatuses
      description: "Returns all Tempus substatuses available for the authenticated user's PBX tenant, including style information."
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: Accept
          in: header
          schema:
            type: string
          example: application/json
      servers:
        -
          url: 'https://cockpit.voxbi.com/api'
          description: 'v2 API server'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: '0.0.0.0:8083'
            Date:
              schema:
                type: string
                example: 'Thu, 12 Oct 2023 12:25:52 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Access-Control-Allow-Origin:
              schema:
                type: string
                example: '*'
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                    name:
                      type: string
                    description:
                      type:
                        - string
                        - 'null'
                    style:
                      type: object
                      description: 'Display style properties such as colors and icon.'
              example:
                -
                  id: 660e8400-e29b-41d4-a716-446655440001
                  name: 'In Meeting'
                  description: null
                  style:
                    background_color: '#ff6f00'
                    font_color: '#ffffff'
                    icon: event
                -
                  id: 660e8400-e29b-41d4-a716-446655440002
                  name: 'On Break'
                  description: null
                  style:
                    background_color: '#0288d1'
                    font_color: '#ffffff'
                    icon: coffee
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
  /cdrs:
    servers:
      -
        url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (production)'
      -
        url: 'https://staging-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (staging)'
      -
        url: 'https://dev-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (development)'
    get:
      tags:
        - CDRs
      summary: 'List call history (CDRs) (user, pbx)'
      operationId: listCdrs
      description: |
        Returns the paginated call history (call detail records) for the
        authenticated principal, newest first. Results are scoped server-side to the
        caller's PBX (and, for a user token, to the caller's own extension), so the
        company scope can never be supplied or overridden by the client.

        With a PBX-owned API key the request spans the whole PBX by default. Pass
        `extension_id` or `extension` to narrow it to the calls made or received by a
        single user's extension. The value is validated against the authenticated PBX
        before use, and the pair is always re-derived server-side, so a mismatched
        `extension` / `extension_id` combination cannot widen the scope. With a user
        personal access token both parameters are ignored: the query is always locked
        to the caller's own extension.

        Authentication accepts either a user personal access token or a PBX-owned
        API key. A PBX API key must carry the `call-history` ability/scope.

        Rate-limited to 120 requests per minute per principal (user, PBX or IP);
        exceeding the limit returns `429 Too Many Requests`.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: extension_id
          in: query
          required: false
          description: |
            Internal ID of the extension whose calls should be returned (the
            extension of the user who made or received the call). PBX API key only,
            and validated to belong to the authenticated PBX; a foreign extension
            returns `403`. Takes precedence over `extension` when both are supplied.
            Omit to span every extension of the PBX. Ignored for user tokens.
          schema:
            type: integer
            format: int64
            example: 15754
        -
          name: extension
          in: query
          required: false
          description: |
            Extension number of the user whose calls should be returned, as an
            alternative to `extension_id`. PBX API key only, and validated to belong
            to the authenticated PBX; a foreign extension returns `403`. Omit to span
            every extension of the PBX. Ignored for user tokens.
          schema:
            type: string
            example: '2039'
        -
          name: extras
          in: query
          required: false
          description: 'When `true`, each record includes the detailed `extras` payload (AI transcription availability and call-timeline data). Defaults to `false` for a lighter, faster response.'
          schema:
            type: boolean
            default: false
            example: false
        -
          name: 'call_type[]'
          in: query
          required: false
          description: 'Filter by call type. Repeatable. One or more of the listed values.'
          schema:
            type: array
            items:
              type: string
              enum:
                - answered
                - missed
                - all
                - incoming
                - outgoing
            example:
              - incoming
        -
          name: start_time
          in: query
          required: false
          description: 'Start of the date/time window (inclusive), in `YYYY-MM-DD HH:MM:SS` format.'
          schema:
            type: string
            example: '2025-01-01 00:00:00'
        -
          name: end_time
          in: query
          required: false
          description: 'End of the date/time window (inclusive), in `YYYY-MM-DD HH:MM:SS` format.'
          schema:
            type: string
            example: '2026-01-12 23:50:59'
        -
          name: search
          in: query
          required: false
          description: 'Full-text search across the call records (names, numbers, and similar fields).'
          schema:
            type: string
            example: 'Customer Support'
        -
          name: id
          in: query
          required: false
          description: 'When supplied, only records with a `cdr_id` greater than this value are returned. Use it to fetch only records newer than the last one you saw, for cheaper incremental polling.'
          schema:
            type: integer
            format: int64
            example: 18457973
        -
          name: page
          in: query
          required: false
          description: 'Page number (1-based).'
          schema:
            type: integer
            minimum: 1
            default: 1
            example: 1
        -
          name: page_size
          in: query
          required: false
          description: 'Number of records per page.'
          schema:
            type: integer
            minimum: 1
            default: 15
            example: 5
        -
          name: remote_extension_number
          in: query
          required: false
          description: 'Filter to calls involving this remote party number or extension.'
          schema:
            type: string
            example: '2041'
      responses:
        200:
          description: 'Paginated call history.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      description: |
                        A single call-history row as returned by the call-history list endpoint. Each
                        record summarises one call leg from the authenticated principal's perspective.
                      required:
                        - cdr_id
                        - type
                        - is_missed_call
                        - is_answered
                        - date
                        - start_time
                        - end_time
                        - duration
                        - billsec
                        - is_transfer_call
                        - is_conference_call
                        - is_recorded
                        - notes_count
                        - transcriptions_available
                        - extras
                      properties:
                        cdr_id:
                          type: string
                          description: 'Unique identifier of the call detail record. Pass it to the detail and call-recording endpoints.'
                          example: '24904193'
                        pbx_user_id:
                          type:
                            - string
                            - 'null'
                          description: 'Identifier of the PBX user the record belongs to.'
                          example: 550e8400-e29b-41d4-a716-446655440010
                        pbx_profile_id:
                          type:
                            - string
                            - 'null'
                          description: 'Profile identifier, when the call is attributed to a specific user profile.'
                          example: null
                        customer_pid:
                          type:
                            - string
                            - 'null'
                          description: 'External customer identifier, when known.'
                          example: null
                        type:
                          type: string
                          enum:
                            - INCOMING
                            - OUTGOING
                          description: 'Direction of the call relative to the PBX.'
                          example: INCOMING
                        is_missed_call:
                          type: boolean
                          description: 'Whether the call was missed (never answered).'
                          example: true
                        is_answered:
                          type: boolean
                          description: 'Whether the call was answered.'
                          example: false
                        remote_person_id:
                          type:
                            - string
                            - 'null'
                          description: 'Identifier of the remote party (the other side of the call), when resolvable.'
                          example: 550e8400-e29b-41d4-a716-446655440020
                        remote_person_name:
                          type:
                            - string
                            - 'null'
                          description: 'Display name of the remote party.'
                          example: 'Customer Support'
                        remote_person_number:
                          type:
                            - string
                            - 'null'
                          description: 'Phone number or extension of the remote party.'
                          example: '+12125550100'
                        via_id:
                          type:
                            - string
                            - 'null'
                          description: 'Identifier of the entity the call was routed via (call flow, queue, or number).'
                          example: 550e8400-e29b-41d4-a716-446655440030
                        via_name:
                          type:
                            - string
                            - 'null'
                          description: 'Display name of the routing entity.'
                          example: 'Main Line'
                        via_number:
                          type:
                            - string
                            - 'null'
                          description: 'Number of the routing entity.'
                          example: '+12125550111'
                        date:
                          type: string
                          format: date
                          description: 'Calendar date the call started, in `YYYY-MM-DD`.'
                          example: '2026-01-12'
                        start_time:
                          type: string
                          description: 'When the call started, in `YYYY-MM-DD HH:MM:SS`.'
                          example: '2026-01-12 15:50:19'
                        answer_time:
                          type:
                            - string
                            - 'null'
                          description: 'When the call was answered, or null if it was never answered.'
                          example: null
                        end_time:
                          type: string
                          description: 'When the call ended, in `YYYY-MM-DD HH:MM:SS`.'
                          example: '2026-01-12 15:50:25'
                        duration:
                          type: integer
                          format: int32
                          description: 'Total call duration in seconds (from start to end).'
                          example: 6
                        billsec:
                          type: integer
                          format: int32
                          description: 'Billable seconds (time the call was actually connected).'
                          example: 0
                        is_transfer_call:
                          type: boolean
                          description: 'Whether the call involved a transfer.'
                          example: false
                        is_conference_call:
                          type: boolean
                          description: 'Whether the call was a conference.'
                          example: false
                        is_recorded:
                          type: boolean
                          description: 'Whether a recording exists for this call.'
                          example: false
                        notes_count:
                          type: integer
                          format: int32
                          description: 'Number of notes attached to this call.'
                          example: 0
                        transcriptions_available:
                          type: boolean
                          description: 'Whether an AI transcription is available for this call.'
                          example: false
                        extras:
                          type: array
                          description: 'Detailed extras (AI transcription and call-timeline data). Populated only when the request sets `extras=true`; otherwise an empty array.'
                          items:
                            type: object
                            additionalProperties: true
                          example: {}
                  pagination:
                    type: object
                    description: 'Pagination metadata for the call-history list response.'
                    properties:
                      current_page:
                        type: integer
                        format: int32
                        description: 'The current page number.'
                        example: 1
                      first_page_url:
                        type:
                          - string
                          - 'null'
                        description: 'URL of the first page.'
                        example: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=1'
                      prev_page_url:
                        type:
                          - string
                          - 'null'
                        description: 'URL of the previous page, or null on the first page.'
                        example: null
                      next_page_url:
                        type:
                          - string
                          - 'null'
                        description: 'URL of the next page, or null on the last page.'
                        example: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=2'
                      last_page_url:
                        type:
                          - string
                          - 'null'
                        description: 'URL of the last page.'
                        example: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=103'
                      last_page:
                        type: integer
                        format: int32
                        description: 'The number of the last page.'
                        example: 103
                      per_page:
                        type: integer
                        format: int32
                        description: 'Number of records per page.'
                        example: 5
                      total:
                        type: integer
                        format: int32
                        description: 'Total number of records across all pages.'
                        example: 515
                      path:
                        type:
                          - string
                          - 'null'
                        description: 'Base path of the paginated resource.'
                        example: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs'
                  cache_hit:
                    type: boolean
                    description: 'Whether this response was served from the short-lived proxy cache.'
                    example: false
                  status:
                    type: boolean
                    description: 'Whether the upstream request succeeded.'
                    example: true
                  message:
                    type: string
                    example: 'CDRs retrieved successfully.'
              example:
                data:
                  -
                    cdr_id: '24904193'
                    pbx_user_id: 550e8400-e29b-41d4-a716-446655440010
                    pbx_profile_id: null
                    customer_pid: null
                    type: INCOMING
                    is_missed_call: true
                    is_answered: false
                    remote_person_id: 550e8400-e29b-41d4-a716-446655440020
                    remote_person_name: 'Customer Support'
                    remote_person_number: '+12125550100'
                    via_id: 550e8400-e29b-41d4-a716-446655440030
                    via_name: 'Main Line'
                    via_number: '+12125550111'
                    date: '2026-01-12'
                    start_time: '2026-01-12 15:50:19'
                    answer_time: null
                    end_time: '2026-01-12 15:50:25'
                    duration: 6
                    billsec: 0
                    is_transfer_call: false
                    is_conference_call: false
                    is_recorded: false
                    notes_count: 0
                    transcriptions_available: false
                    extras: {}
                  -
                    cdr_id: '24890011'
                    pbx_user_id: 550e8400-e29b-41d4-a716-446655440010
                    pbx_profile_id: null
                    customer_pid: null
                    type: OUTGOING
                    is_missed_call: false
                    is_answered: true
                    remote_person_id: 550e8400-e29b-41d4-a716-446655440021
                    remote_person_name: 'Sales Team'
                    remote_person_number: '+12125550101'
                    via_id: 550e8400-e29b-41d4-a716-446655440030
                    via_name: 'Main Line'
                    via_number: '+12125550111'
                    date: '2026-01-05'
                    start_time: '2026-01-05 15:33:09'
                    answer_time: '2026-01-05 15:33:14'
                    end_time: '2026-01-05 15:38:02'
                    duration: 293
                    billsec: 293
                    is_transfer_call: false
                    is_conference_call: false
                    is_recorded: true
                    notes_count: 0
                    transcriptions_available: true
                    extras: {}
                pagination:
                  current_page: 1
                  first_page_url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=1'
                  prev_page_url: null
                  next_page_url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=2'
                  last_page_url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs?page=103'
                  last_page: 103
                  per_page: 5
                  total: 515
                  path: 'https://cockpit.voxbi.com/api/v1/cdrs-utility/cdrs'
                cache_hit: false
                status: true
                message: 'CDRs retrieved successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Either the presented PBX API key does not carry the required
            `call-history` ability/scope, or the requested `extension_id` /
            `extension` does not belong to the authenticated PBX. A user token whose
            account has no extension assigned is rejected here as well.
        429:
          description: 'Too many requests. The endpoint is rate-limited to 120 requests per minute per principal. Retry after the window indicated by the `Retry-After` response header.'
  '/cdrs/detail/{id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (production)'
      -
        url: 'https://staging-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (staging)'
      -
        url: 'https://dev-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (development)'
    get:
      tags:
        - CDRs
      summary: 'Get call detail by ID (user, pbx)'
      operationId: getCdrDetail
      description: |
        Returns the full detail of a single call, including each receiving leg, the
        call-flow timeline, recording-file references, notes, and AI transcription
        results. Scoped server-side to the caller's PBX.

        Authentication accepts either a user personal access token or a PBX-owned
        API key. A PBX API key must carry the `call-history` ability/scope.

        Rate-limited to 120 requests per minute per principal.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          description: 'The `cdr_id` of the call, as returned by the call-history list.'
          schema:
            type: integer
            format: int64
            example: 24904193
      responses:
        200:
          description: 'The call detail.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      Full detail of a single call, including every receiving leg, the call-flow
                      timeline, recording references, notes, and AI transcription results.
                    required:
                      - id
                      - type
                      - date
                      - start_time
                      - end_time
                      - duration
                      - billsec
                      - caller
                      - receivers
                    properties:
                      id:
                        type: integer
                        format: int64
                        description: 'Unique identifier of the call detail record.'
                        example: 24904193
                      company_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) the call belongs to.'
                        example: 550e8400-e29b-41d4-a716-446655440000
                      type:
                        type: string
                        enum:
                          - INCOMING
                          - OUTGOING
                        description: 'Direction of the call.'
                        example: OUTGOING
                      date:
                        type: string
                        format: date
                        description: 'Calendar date the call started.'
                        example: '2026-01-12'
                      start_time:
                        type: string
                        description: 'When the call started, in `YYYY-MM-DD HH:MM:SS`.'
                        example: '2026-01-12 15:50:19'
                      answer_time:
                        type:
                          - string
                          - 'null'
                        description: 'When the call was answered, or null if never answered.'
                        example: null
                      end_time:
                        type: string
                        description: 'When the call ended, in `YYYY-MM-DD HH:MM:SS`.'
                        example: '2026-01-12 15:50:25'
                      duration:
                        type: integer
                        format: int32
                        description: 'Total duration in seconds.'
                        example: 6
                      billsec:
                        type: integer
                        format: int32
                        description: 'Billable seconds.'
                        example: 0
                      is_transfer_call:
                        type: boolean
                        example: false
                      is_internal:
                        type: boolean
                        description: 'Whether both parties are internal to the PBX.'
                        example: true
                      is_conference_call:
                        type: boolean
                        example: false
                      conference:
                        type: array
                        description: 'Conference participant legs, when the call was a conference.'
                        items:
                          type: object
                          additionalProperties: true
                        example: {}
                      is_recording_file_exists:
                        type: boolean
                        description: 'Whether a recording file exists for this call.'
                        example: false
                      recording_file:
                        type: object
                        description: |
                          A call-recording file reference. The recording can only be downloaded with a
                          bearer token (see the call-recording endpoint); the `path` and `download_url`
                          are populated only when a recording exists.
                        properties:
                          name:
                            type: string
                            description: 'File name of the recording, or an empty string when none exists.'
                            example: ''
                          path:
                            type:
                              - string
                              - 'null'
                            description: 'Storage path of the recording, used as the `path` query parameter on the call-recording endpoint.'
                            example: null
                          download_url:
                            type:
                              - string
                              - 'null'
                            description: 'Direct download URL of the recording, when available.'
                            example: null
                          hint:
                            type: string
                            description: 'Human-readable note describing which part of the call this recording covers and how to download it.'
                            example: 'This recording file is for the entire call, including both caller and callee recordings. You can only download it using your bearer token.'
                      recording_file_path_caller:
                        type: object
                        description: |
                          A call-recording file reference. The recording can only be downloaded with a
                          bearer token (see the call-recording endpoint); the `path` and `download_url`
                          are populated only when a recording exists.
                        properties:
                          name:
                            type: string
                            description: 'File name of the recording, or an empty string when none exists.'
                            example: ''
                          path:
                            type:
                              - string
                              - 'null'
                            description: 'Storage path of the recording, used as the `path` query parameter on the call-recording endpoint.'
                            example: null
                          download_url:
                            type:
                              - string
                              - 'null'
                            description: 'Direct download URL of the recording, when available.'
                            example: null
                          hint:
                            type: string
                            description: 'Human-readable note describing which part of the call this recording covers and how to download it.'
                            example: 'This recording file is for the entire call, including both caller and callee recordings. You can only download it using your bearer token.'
                      recording_file_path_callee:
                        type: object
                        description: |
                          A call-recording file reference. The recording can only be downloaded with a
                          bearer token (see the call-recording endpoint); the `path` and `download_url`
                          are populated only when a recording exists.
                        properties:
                          name:
                            type: string
                            description: 'File name of the recording, or an empty string when none exists.'
                            example: ''
                          path:
                            type:
                              - string
                              - 'null'
                            description: 'Storage path of the recording, used as the `path` query parameter on the call-recording endpoint.'
                            example: null
                          download_url:
                            type:
                              - string
                              - 'null'
                            description: 'Direct download URL of the recording, when available.'
                            example: null
                          hint:
                            type: string
                            description: 'Human-readable note describing which part of the call this recording covers and how to download it.'
                            example: 'This recording file is for the entire call, including both caller and callee recordings. You can only download it using your bearer token.'
                      caller:
                        type: object
                        description: 'The originating party.'
                        properties:
                          id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            example: 550e8400-e29b-41d4-a716-446655440041
                          name:
                            type: string
                            example: 'Customer Support'
                          number:
                            type: string
                            example: '2041'
                      receivers:
                        type: array
                        description: 'Every receiving leg that was rung for this call.'
                        items:
                          type: object
                          description: 'One receiving leg of a call (a destination that was rung), with its own timing and routing.'
                          properties:
                            id:
                              type:
                                - string
                                - 'null'
                              description: 'Identifier of the receiver (user, extension, or external party).'
                              example: 550e8400-e29b-41d4-a716-446655440040
                            status:
                              type: string
                              enum:
                                - TRIGGERED
                                - RINGING
                                - ANSWERED
                                - MISSED
                                - BUSY
                                - FAILED
                              description: 'Outcome for this receiving leg.'
                              example: TRIGGERED
                            name:
                              type: string
                              description: 'Display name of the receiver, or an empty string when unknown.'
                              example: 'Sales Team'
                            number:
                              type: string
                              description: 'Phone number or extension of the receiver.'
                              example: '2039'
                            start_time:
                              type: string
                              description: 'When this leg started ringing, in `YYYY-MM-DD HH:MM:SS`.'
                              example: '2026-01-12 15:50:19'
                            answer_time:
                              type:
                                - string
                                - 'null'
                              description: 'When this leg was answered, or null if never answered.'
                              example: '2026-01-12 15:50:19'
                            end_time:
                              type: string
                              description: 'When this leg ended, in `YYYY-MM-DD HH:MM:SS`.'
                              example: '2026-01-12 15:50:25'
                            duration:
                              type: integer
                              format: int32
                              description: 'Duration of this leg in seconds.'
                              example: 6
                            billsec:
                              type: integer
                              format: int32
                              description: 'Billable seconds for this leg.'
                              example: 6
                            via_id:
                              type:
                                - string
                                - 'null'
                              description: 'Identifier of the entity this leg was routed via.'
                              example: 550e8400-e29b-41d4-a716-446655440030
                            via_name:
                              type:
                                - string
                                - 'null'
                              description: 'Display name of the routing entity.'
                              example: 'Main Line'
                            via_number:
                              type:
                                - string
                                - 'null'
                              description: 'Number of the routing entity.'
                              example: '+12125550111'
                            via_type:
                              type:
                                - string
                                - 'null'
                              enum:
                                - CALL_FLOW
                                - QUEUE
                                - TWINNING
                                - IVR
                                - null
                              description: 'How this leg was reached, or null when not applicable.'
                              example: CALL_FLOW
                      call_flow:
                        type: array
                        description: 'Human-readable, ordered timeline of what happened during the call.'
                        items:
                          type: object
                          properties:
                            color:
                              type: string
                              description: 'UI severity hint for the timeline entry.'
                              enum:
                                - info
                                - secondary
                                - success
                                - warning
                                - danger
                              example: info
                            text:
                              type: string
                              description: 'Primary timeline message.'
                              example: 'OUTGOING - Call started by Customer Support (2041)'
                            sub_text:
                              type:
                                - string
                                - 'null'
                              description: 'Secondary timeline detail.'
                              example: null
                            time:
                              type: string
                              description: 'When the timeline entry occurred, in `YYYY-MM-DD HH:MM:SS`.'
                              example: '2026-01-12 15:50:19'
                      notes:
                        type: array
                        description: 'Notes attached to the call.'
                        items:
                          type: object
                          additionalProperties: true
                        example: {}
                      transcriptions:
                        type:
                          - object
                          - 'null'
                        description: 'AI transcription result, or null when none is available.'
                        additionalProperties: true
                        example: null
                      ai_processing_errors:
                        type: array
                        description: 'Errors raised while AI-processing the call, if any.'
                        items:
                          type: object
                          additionalProperties: true
                        example: {}
                  status:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: CDRs
              example:
                data:
                  id: 24904193
                  company_id: 550e8400-e29b-41d4-a716-446655440000
                  type: OUTGOING
                  date: '2026-01-12'
                  start_time: '2026-01-12 15:50:19'
                  answer_time: null
                  end_time: '2026-01-12 15:50:25'
                  duration: 6
                  billsec: 0
                  is_transfer_call: false
                  is_internal: true
                  is_conference_call: false
                  conference: {}
                  is_recording_file_exists: false
                  recording_file:
                    name: ''
                    path: null
                    download_url: null
                    hint: 'This recording file is for the entire call, including both caller and callee recordings. You can only download it using your bearer token.'
                  recording_file_path_caller:
                    name: ''
                    path: null
                    download_url: null
                    hint: 'This recording file is for the caller part of the call. You can only download it using your bearer token.'
                  recording_file_path_callee:
                    name: ''
                    path: null
                    download_url: null
                    hint: 'This recording file is for the callee part of the call. You can only download it using your bearer token.'
                  caller:
                    id: 550e8400-e29b-41d4-a716-446655440041
                    name: 'Customer Support'
                    number: '2041'
                  receivers:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440042
                      status: TRIGGERED
                      name: 'Sales Team'
                      number: '2039'
                      start_time: '2026-01-12 15:50:19'
                      answer_time: '2026-01-12 15:50:19'
                      end_time: '2026-01-12 15:50:25'
                      duration: 6
                      billsec: 6
                      via_id: 550e8400-e29b-41d4-a716-446655440041
                      via_name: 'Customer Support'
                      via_number: '2041'
                      via_type: CALL_FLOW
                    -
                      id: 550e8400-e29b-41d4-a716-446655440043
                      status: MISSED
                      name: ''
                      number: '+12125550100'
                      start_time: '2026-01-12 15:50:21'
                      answer_time: null
                      end_time: '2026-01-12 15:50:25'
                      duration: 6
                      billsec: 0
                      via_id: 550e8400-e29b-41d4-a716-446655440041
                      via_name: 'Customer Support'
                      via_number: '2041'
                      via_type: TWINNING
                  call_flow:
                    -
                      color: info
                      text: 'OUTGOING - Call started by Customer Support (2041)'
                      sub_text: null
                      time: '2026-01-12 15:50:19'
                    -
                      color: secondary
                      text: 'Triggered Sales Team (2039)'
                      sub_text: 'Via [CALL_FLOW] - Customer Support (2041)'
                      time: '2026-01-12 15:50:19'
                    -
                      color: danger
                      text: 'Missed by Sales Team (2039)'
                      sub_text: 'Via Customer Support (2041)'
                      time: '2026-01-12 15:50:20'
                    -
                      color: info
                      text: 'Call Finished'
                      sub_text: null
                      time: '2026-01-12 15:50:25'
                  notes: {}
                  transcriptions: null
                  ai_processing_errors: {}
                status: true
                message: CDRs
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The presented PBX API key does not carry the required `call-history` ability/scope.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        429:
          description: 'Too many requests. Rate-limited to 120 requests per minute per principal.'
  /call-recording:
    servers:
      -
        url: 'https://cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (production)'
      -
        url: 'https://staging-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (staging)'
      -
        url: 'https://dev-cockpit.voxbi.com/api/v1/cdrs-utility'
        description: 'CDR utility API server (development)'
    get:
      tags:
        - CDRs
      summary: 'Download a call recording (user, pbx)'
      operationId: getCdrCallRecording
      description: |
        Streams the audio recording for a call. By default the recording for the
        given call `id` is returned. To fetch a specific recording variant (caller
        leg, callee leg, or the combined file), pass its `path` (obtained from the
        `recording_file*` references on the call-detail or, in the list, when
        `extras=true`).

        Authentication accepts either a user personal access token or a PBX-owned
        API key. A PBX API key must carry the `call-history` ability/scope.

        Rate-limited to 120 requests per minute per principal.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: id
          in: query
          required: true
          description: 'The `cdr_id` of the call whose recording to download.'
          schema:
            type: integer
            format: int64
            example: 24624794
        -
          name: path
          in: query
          required: false
          description: |
            Specific recording-file path to download (the `path` value from a
            `recording_file`, `recording_file_path_caller`, or
            `recording_file_path_callee` reference). Omit to download the default
            recording for the call.
          schema:
            type: string
            example: recordings/2026/01/12/24624794-full.wav
      responses:
        200:
          description: 'The recording audio stream.'
          content:
            audio/wav:
              schema:
                type: string
                format: binary
            audio/mpeg:
              schema:
                type: string
                format: binary
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The presented PBX API key does not carry the required `call-history` ability/scope.'
        404:
          description: 'No recording exists for the given call or path.'
        429:
          description: 'Too many requests. Rate-limited to 120 requests per minute per principal.'
  /AndroidNfc/getUser:
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusInternal
      summary: 'Get user by NFC badge'
      operationId: getTempusAndroidNfc
      description: |
        Returns a paginated list of tempus android nfc. Use the standard `search`, `sort`, `page`,
        and `perPage` query parameters; use `filter[key]=value` to narrow the result set.
        Multi-tenant scoping is enforced. Requires a PBX API-key token carrying the `terminals` ability.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  currentStatus:
                    type:
                      - object
                      - 'null'
                    description: |
                      The user's ongoing timepoint status (tempus StatusResource) with timepoint_id, start_time, created_at and timepoint_location appended. Null when the user has no ongoing timepoint.
                  userInfo:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      bearerToken:
                        type: string
                        description: 'Freshly issued Sanctum token for the badge session.'
                      displayName:
                        type:
                          - string
                          - 'null'
                  layout:
                    type:
                      - object
                      - 'null'
                    description: |
                      Terminal layout (tempus LayoutResource) with options, layout and preview_url. Null when no layout is configured.
              example:
                currentStatus:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  mxvp_user_id: 550e8400-e29b-41d4-a716-446655440001
                  name: Working
                  icon: 'la la-briefcase'
                  fontcolor: '#ffffff'
                  backgroundcolor: '#2e7d32'
                  payable: true
                  availability: available
                  sub_statuses: {}
                  timepoint_id: 550e8400-e29b-41d4-a716-446655440020
                  start_time: '2026-07-16T08:00:00.000000Z'
                  created_at: '2026-07-16T08:00:00.000000Z'
                  timepoint_location: 550e8400-e29b-41d4-a716-446655440030
                userInfo:
                  id: 550e8400-e29b-41d4-a716-446655440002
                  bearerToken: 42|aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd
                  displayName: 'Jane Smith'
                layout:
                  options:
                    geoEnable: true
                    geoForce: false
                    postAction: false
                    updateTimer: 5000
                  layout:
                    id: 550e8400-e29b-41d4-a716-446655440040
                    name: 'Default Tempus'
                    type: default
                    tl_layouts_statuses: {}
                  preview_url: 'https://cockpit.voxbi.com/layout-preview/550e8400-e29b-41d4-a716-446655440040'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
    post:
      tags:
        - TempusInternal
      summary: 'Log a terminal NFC event'
      operationId: postTempusAndroidNfc
      description: |
        Creates a new tempus android nfc. Validation rules and required fields are defined in the
        request body schema below. Requires a PBX API-key token carrying the `terminals` ability.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                badge_id:
                  type: string
                  example: BADGE123
                terminal_id:
                  type: string
                  example: TERM01
                timestamp:
                  type: string
                  format: date-time
                  example: '2024-01-15T08:30:00Z'
            example:
              badge_id: BADGE123
              terminal_id: TERM01
              timestamp: '2024-01-15T08:30:00Z'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      created:
                        type: string
                        description: 'Creation timestamp, formatted `Y-m-d H:i:s`.'
              example:
                success: true
                message: 'Terminal log created successfully'
                data:
                  id: 550e8400-e29b-41d4-a716-446655440050
                  created: '2026-07-16 09:15:42'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/terminal/{mac_address}/badge':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusInternal
      summary: 'Get tablet session (grid layout format)'
      operationId: postTempusTerminalBadge
      description: |
        Returns the tablet session for a scanned badge: current status, work-time
        summary, layout and terminal location. Requires a PBX API-key token with the
        `terminals` ability.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: mac_address
          in: path
          required: true
          description: "The tablet's MAC address (any format; case-insensitive)."
          schema:
            type: string
          example: '001122334455'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - badge_identifier
              properties:
                badge_identifier:
                  type: string
                  description: 'The scanned NFC badge identifier.'
            example:
              badge_identifier: BADGE-0001
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  current_status:
                    type:
                      - object
                      - 'null'
                    description: 'The status the user is currently in; null when there is no ongoing timepoint.'
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                      description:
                        type:
                          - string
                          - 'null'
                      style:
                        type: object
                      metadata:
                        type: object
                        properties:
                          availability:
                            type:
                              - string
                              - 'null'
                          allow_multiselect:
                            type: boolean
                          substatus_selection_mandatory:
                            type: boolean
                      location_ids:
                        type: array
                        items:
                          type: string
                          format: uuid
                      substatus_ids:
                        type: array
                        items:
                          type: string
                          format: uuid
                  user_info:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      bearer_token:
                        type: string
                        description: 'Freshly issued Sanctum token for the badge session.'
                      display_name:
                        type:
                          - string
                          - 'null'
                  work_times:
                    type: object
                    description: 'Current-day work-time summary (HH:MM:SS).'
                    properties:
                      daily:
                        type: string
                      min_daily:
                        type: string
                      weekly:
                        type: string
                      min_weekly:
                        type: string
                      monthly:
                        type: string
                      min_monthly:
                        type: string
                      lunch:
                        type: string
                  layout:
                    type:
                      - object
                      - 'null'
                    description: 'The assigned layout; null when no active layout is configured.'
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                      grid_size:
                        type: object
                        properties:
                          rows:
                            type: integer
                          columns:
                            type: integer
                      statuses:
                        type: array
                        items:
                          type: object
                      substatuses:
                        type: object
                  location:
                    type:
                      - object
                      - 'null'
                    description: "The terminal's location; null when it has none or no terminal matched."
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                      description:
                        type:
                          - string
                          - 'null'
              example:
                current_status:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  name: Working
                  description: 'Regular working time'
                  style:
                    icon_class: 'la la-briefcase'
                    bg_color: '#2e7d32'
                    font_color: '#ffffff'
                  metadata:
                    availability: available
                    allow_multiselect: false
                    substatus_selection_mandatory: false
                  location_ids: {}
                  substatus_ids: {}
                user_info:
                  id: 550e8400-e29b-41d4-a716-446655440002
                  bearer_token: 42|aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd
                  display_name: 'Jane Smith'
                work_times:
                  daily: '07:30:00'
                  min_daily: '08:00:00'
                  weekly: '37:30:00'
                  min_weekly: '40:00:00'
                  monthly: '150:00:00'
                  min_monthly: '160:00:00'
                  lunch: '00:30:00'
                layout:
                  id: 550e8400-e29b-41d4-a716-446655440040
                  name: 'Default Tempus'
                  grid_size:
                    rows: 3
                    columns: 3
                  statuses: {}
                  substatuses: {}
                location:
                  id: 550e8400-e29b-41d4-a716-446655440030
                  name: 'Head Office'
                  description: 'Main office location'
        400:
          description: 'Missing required field (badge_identifier).'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: 'Missing required field: badge_identifier'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The matched terminal exists but is not active. No session is returned.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: 'Terminal exists but is not active'
  /TimeLogger/getBadge:
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusInternal
      summary: 'Get badge data (TimeLogger)'
      operationId: getTempusTimeLogger
      description: |
        Returns a paginated list of tempus time logger. Use the standard `search`, `sort`, `page`,
        and `perPage` query parameters; use `filter[key]=value` to narrow the result set.
        Multi-tenant scoping is enforced. Requires a PBX API-key token carrying the `terminals` ability.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      full_name:
                        type:
                          - string
                          - 'null'
                      extension_number:
                        type:
                          - string
                          - 'null'
                        description: "The user's extension number, or null when none is assigned."
                      email:
                        type:
                          - string
                          - 'null'
                      active:
                        type: boolean
                  auth_info:
                    type: object
                    properties:
                      bearerToken:
                        type: string
                        description: 'Freshly issued Sanctum token for the badge session.'
                      pbx_id:
                        type: string
                        format: uuid
              example:
                user:
                  id: 550e8400-e29b-41d4-a716-446655440002
                  full_name: 'Jane Smith'
                  extension_number: '1042'
                  email: jane.smith@example.com
                  active: true
                auth_info:
                  bearerToken: 43|ZyXwVuTsRqPoNmLkJiHgFeDcBa9876543210ZyXw
                  pbx_id: 550e8400-e29b-41d4-a716-446655440001
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
    post:
      tags:
        - TempusInternal
      summary: 'Submit badge data (TimeLogger)'
      operationId: postTempusTimeLogger
      description: |
        Creates a new tempus time logger. Validation rules and required fields are defined in the
        request body schema below. Requires a PBX API-key token carrying the `terminals` ability.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                badge_id:
                  type: string
                  example: BADGE123
                terminal_id:
                  type: string
                  example: TERM01
            example:
              badge_id: BADGE123
              terminal_id: TERM01
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      full_name:
                        type:
                          - string
                          - 'null'
                      extension_number:
                        type:
                          - string
                          - 'null'
                        description: "The user's extension number, or null when none is assigned."
                      email:
                        type:
                          - string
                          - 'null'
                      active:
                        type: boolean
                  auth_info:
                    type: object
                    properties:
                      bearerToken:
                        type: string
                        description: 'Freshly issued Sanctum token for the badge session.'
                      pbx_id:
                        type: string
                        format: uuid
              example:
                user:
                  id: 550e8400-e29b-41d4-a716-446655440002
                  full_name: 'Jane Smith'
                  extension_number: '1042'
                  email: jane.smith@example.com
                  active: true
                auth_info:
                  bearerToken: 43|ZyXwVuTsRqPoNmLkJiHgFeDcBa9876543210ZyXw
                  pbx_id: 550e8400-e29b-41d4-a716-446655440001
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /recurring-transactions/preview-next-run:
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusInternal
      summary: 'Preview the next run of a recurring transaction'
      operationId: postTempusRecurringTransactionPreviewNextRun
      description: |
        Computes the next materialisation date for a given frequency without creating a
        template. Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - frequency
              properties:
                frequency:
                  type: string
                  enum:
                    - monthly_start
                    - yearly_start
                run_once:
                  type: boolean
                from:
                  type: string
                  format: date
                  description: 'Optional anchor date. Defaults to today.'
            example:
              frequency: monthly_start
              from: '2026-06-15'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  next_run_at:
                    type: string
                    format: date-time
                  next_run_at_human:
                    type: string
                  timezone:
                    type: string
              example:
                next_run_at: '2026-07-01T00:00:00+00:00'
                next_run_at_human: 'July 1, 2026'
                timezone: Europe/Luxembourg
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  /recurring-transactions:
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusInternal
      summary: 'List recurring transactions'
      operationId: listTempusRecurringTransactions
      description: |
        Returns a paginated list of recurring transaction templates for the authenticated PBX,
        ordered by creation date descending. Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: employee_id
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: 'Filter by Tempus employee.'
        -
          name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - paused
              - completed
              - failed
        -
          name: frequency
          in: query
          required: false
          schema:
            type: string
            enum:
              - monthly_start
              - yearly_start
        -
          name: run_once
          in: query
          required: false
          schema:
            type: boolean
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            default: 25
            minimum: 1
            maximum: 100
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'Unique recurring transaction template identifier.'
                          example: 550e8400-e29b-41d4-a716-446655440000
                        pbx_id:
                          type: string
                          format: uuid
                          description: 'PBX tenant the template belongs to.'
                          example: 550e8400-e29b-41d4-a716-446655440001
                        employee_id:
                          type: string
                          format: uuid
                          description: 'Tempus employee the materialised transactions are booked against.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        type:
                          type: string
                          description: 'Transaction type key.'
                          example: bonus
                        sub_type:
                          type:
                            - string
                            - 'null'
                          description: 'Optional sub-type key.'
                          example: annual
                        absence_type_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                          example: null
                        amount:
                          type: number
                          format: float
                          description: 'Amount applied on each run. Always greater than zero.'
                          example: 8
                        tr_type:
                          type: string
                          enum:
                            - credit
                            - debit
                          description: 'Whether each run credits or debits the balance.'
                          example: credit
                        note:
                          type:
                            - string
                            - 'null'
                          description: 'Free-text note carried onto each materialised transaction.'
                          example: 'Monthly meal allowance'
                        frequency:
                          type: string
                          enum:
                            - monthly_start
                            - yearly_start
                          description: 'When the template materialises a transaction.'
                          example: monthly_start
                        run_once:
                          type: boolean
                          description: 'When true the template runs a single time and then completes.'
                          example: false
                        status:
                          type: string
                          enum:
                            - active
                            - paused
                            - completed
                            - failed
                          description: 'Lifecycle status of the template.'
                          example: active
                        failure_reason:
                          type:
                            - string
                            - 'null'
                          description: 'Populated when the last run failed.'
                          example: null
                        next_run_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Next scheduled materialisation, in ISO 8601.'
                          example: '2026-07-01T00:00:00+00:00'
                        last_run_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          description: 'Last materialisation timestamp, in ISO 8601.'
                          example: null
                        last_transaction_id:
                          type:
                            - string
                            - 'null'
                          description: 'Identifier of the most recently materialised Tempus transaction.'
                          example: null
                        created_by_user_id:
                          type:
                            - string
                            - 'null'
                          description: 'User who created the template. Always null when created through the API key flow.'
                          example: null
                        created_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2026-06-01T08:29:07+00:00'
                        updated_at:
                          type:
                            - string
                            - 'null'
                          format: date-time
                          example: '2026-06-01T08:29:07+00:00'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
    post:
      tags:
        - TempusInternal
      summary: 'Create a recurring transaction'
      operationId: createTempusRecurringTransaction
      description: |
        Creates a recurring transaction template for the authenticated PBX. The template is
        activated immediately and its first `next_run_at` is computed from the frequency.
        The PBX is resolved from the API key, so `pbx_id` is never part of the request body.
        Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - employee_id
                - type
                - amount
                - tr_type
                - frequency
              properties:
                employee_id:
                  type: string
                  format: uuid
                  description: 'Must be an active Tempus employee of the authenticated PBX.'
                type:
                  type: string
                sub_type:
                  type:
                    - string
                    - 'null'
                absence_type_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Must be an absence type of the authenticated PBX, when supplied.'
                amount:
                  type: number
                  format: float
                  description: 'Greater than zero.'
                tr_type:
                  type: string
                  enum:
                    - credit
                    - debit
                note:
                  type:
                    - string
                    - 'null'
                  maxLength: 65535
                frequency:
                  type: string
                  enum:
                    - monthly_start
                    - yearly_start
                run_once:
                  type: boolean
            example:
              employee_id: 550e8400-e29b-41d4-a716-446655440002
              type: bonus
              amount: 8
              tr_type: credit
              frequency: monthly_start
              run_once: false
              note: 'Monthly meal allowance'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique recurring transaction template identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX tenant the template belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  employee_id:
                    type: string
                    format: uuid
                    description: 'Tempus employee the materialised transactions are booked against.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  type:
                    type: string
                    description: 'Transaction type key.'
                    example: bonus
                  sub_type:
                    type:
                      - string
                      - 'null'
                    description: 'Optional sub-type key.'
                    example: annual
                  absence_type_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                    example: null
                  amount:
                    type: number
                    format: float
                    description: 'Amount applied on each run. Always greater than zero.'
                    example: 8
                  tr_type:
                    type: string
                    enum:
                      - credit
                      - debit
                    description: 'Whether each run credits or debits the balance.'
                    example: credit
                  note:
                    type:
                      - string
                      - 'null'
                    description: 'Free-text note carried onto each materialised transaction.'
                    example: 'Monthly meal allowance'
                  frequency:
                    type: string
                    enum:
                      - monthly_start
                      - yearly_start
                    description: 'When the template materialises a transaction.'
                    example: monthly_start
                  run_once:
                    type: boolean
                    description: 'When true the template runs a single time and then completes.'
                    example: false
                  status:
                    type: string
                    enum:
                      - active
                      - paused
                      - completed
                      - failed
                    description: 'Lifecycle status of the template.'
                    example: active
                  failure_reason:
                    type:
                      - string
                      - 'null'
                    description: 'Populated when the last run failed.'
                    example: null
                  next_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Next scheduled materialisation, in ISO 8601.'
                    example: '2026-07-01T00:00:00+00:00'
                  last_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last materialisation timestamp, in ISO 8601.'
                    example: null
                  last_transaction_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the most recently materialised Tempus transaction.'
                    example: null
                  created_by_user_id:
                    type:
                      - string
                      - 'null'
                    description: 'User who created the template. Always null when created through the API key flow.'
                    example: null
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/recurring-transactions/{id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusInternal
      summary: 'Get a recurring transaction'
      operationId: getTempusRecurringTransaction
      description: 'Returns a single recurring transaction template. Server-to-server only (PBX API key).'
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique recurring transaction template identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX tenant the template belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  employee_id:
                    type: string
                    format: uuid
                    description: 'Tempus employee the materialised transactions are booked against.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  type:
                    type: string
                    description: 'Transaction type key.'
                    example: bonus
                  sub_type:
                    type:
                      - string
                      - 'null'
                    description: 'Optional sub-type key.'
                    example: annual
                  absence_type_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                    example: null
                  amount:
                    type: number
                    format: float
                    description: 'Amount applied on each run. Always greater than zero.'
                    example: 8
                  tr_type:
                    type: string
                    enum:
                      - credit
                      - debit
                    description: 'Whether each run credits or debits the balance.'
                    example: credit
                  note:
                    type:
                      - string
                      - 'null'
                    description: 'Free-text note carried onto each materialised transaction.'
                    example: 'Monthly meal allowance'
                  frequency:
                    type: string
                    enum:
                      - monthly_start
                      - yearly_start
                    description: 'When the template materialises a transaction.'
                    example: monthly_start
                  run_once:
                    type: boolean
                    description: 'When true the template runs a single time and then completes.'
                    example: false
                  status:
                    type: string
                    enum:
                      - active
                      - paused
                      - completed
                      - failed
                    description: 'Lifecycle status of the template.'
                    example: active
                  failure_reason:
                    type:
                      - string
                      - 'null'
                    description: 'Populated when the last run failed.'
                    example: null
                  next_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Next scheduled materialisation, in ISO 8601.'
                    example: '2026-07-01T00:00:00+00:00'
                  last_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last materialisation timestamp, in ISO 8601.'
                    example: null
                  last_transaction_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the most recently materialised Tempus transaction.'
                    example: null
                  created_by_user_id:
                    type:
                      - string
                      - 'null'
                    description: 'User who created the template. Always null when created through the API key flow.'
                    example: null
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    patch:
      tags:
        - TempusInternal
      summary: 'Update a recurring transaction'
      operationId: patchTempusRecurringTransaction
      description: |
        Updates the mutable fields of a recurring transaction template. Only `amount`, `tr_type`,
        `note`, `frequency` and `run_once` can be changed; `employee_id`, `type`, `sub_type`,
        `absence_type_id` and `pbx_id` are fixed at creation. Changing `frequency` recomputes the
        next run. Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: number
                  format: float
                  description: 'Greater than zero.'
                tr_type:
                  type: string
                  enum:
                    - credit
                    - debit
                note:
                  type:
                    - string
                    - 'null'
                  maxLength: 65535
                frequency:
                  type: string
                  enum:
                    - monthly_start
                    - yearly_start
                run_once:
                  type: boolean
            example:
              amount: 10
              note: 'Updated allowance'
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique recurring transaction template identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX tenant the template belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  employee_id:
                    type: string
                    format: uuid
                    description: 'Tempus employee the materialised transactions are booked against.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  type:
                    type: string
                    description: 'Transaction type key.'
                    example: bonus
                  sub_type:
                    type:
                      - string
                      - 'null'
                    description: 'Optional sub-type key.'
                    example: annual
                  absence_type_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                    example: null
                  amount:
                    type: number
                    format: float
                    description: 'Amount applied on each run. Always greater than zero.'
                    example: 8
                  tr_type:
                    type: string
                    enum:
                      - credit
                      - debit
                    description: 'Whether each run credits or debits the balance.'
                    example: credit
                  note:
                    type:
                      - string
                      - 'null'
                    description: 'Free-text note carried onto each materialised transaction.'
                    example: 'Monthly meal allowance'
                  frequency:
                    type: string
                    enum:
                      - monthly_start
                      - yearly_start
                    description: 'When the template materialises a transaction.'
                    example: monthly_start
                  run_once:
                    type: boolean
                    description: 'When true the template runs a single time and then completes.'
                    example: false
                  status:
                    type: string
                    enum:
                      - active
                      - paused
                      - completed
                      - failed
                    description: 'Lifecycle status of the template.'
                    example: active
                  failure_reason:
                    type:
                      - string
                      - 'null'
                    description: 'Populated when the last run failed.'
                    example: null
                  next_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Next scheduled materialisation, in ISO 8601.'
                    example: '2026-07-01T00:00:00+00:00'
                  last_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last materialisation timestamp, in ISO 8601.'
                    example: null
                  last_transaction_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the most recently materialised Tempus transaction.'
                    example: null
                  created_by_user_id:
                    type:
                      - string
                      - 'null'
                    description: 'User who created the template. Always null when created through the API key flow.'
                    example: null
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - TempusInternal
      summary: 'Delete a recurring transaction'
      operationId: deleteTempusRecurringTransaction
      description: 'Soft-deletes a recurring transaction template. Server-to-server only (PBX API key).'
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        204:
          description: 'No Content'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/recurring-transactions/{id}/pause':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusInternal
      summary: 'Pause a recurring transaction'
      operationId: postTempusRecurringTransactionPause
      description: 'Sets the template status to `paused`. Server-to-server only (PBX API key).'
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique recurring transaction template identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX tenant the template belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  employee_id:
                    type: string
                    format: uuid
                    description: 'Tempus employee the materialised transactions are booked against.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  type:
                    type: string
                    description: 'Transaction type key.'
                    example: bonus
                  sub_type:
                    type:
                      - string
                      - 'null'
                    description: 'Optional sub-type key.'
                    example: annual
                  absence_type_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                    example: null
                  amount:
                    type: number
                    format: float
                    description: 'Amount applied on each run. Always greater than zero.'
                    example: 8
                  tr_type:
                    type: string
                    enum:
                      - credit
                      - debit
                    description: 'Whether each run credits or debits the balance.'
                    example: credit
                  note:
                    type:
                      - string
                      - 'null'
                    description: 'Free-text note carried onto each materialised transaction.'
                    example: 'Monthly meal allowance'
                  frequency:
                    type: string
                    enum:
                      - monthly_start
                      - yearly_start
                    description: 'When the template materialises a transaction.'
                    example: monthly_start
                  run_once:
                    type: boolean
                    description: 'When true the template runs a single time and then completes.'
                    example: false
                  status:
                    type: string
                    enum:
                      - active
                      - paused
                      - completed
                      - failed
                    description: 'Lifecycle status of the template.'
                    example: active
                  failure_reason:
                    type:
                      - string
                      - 'null'
                    description: 'Populated when the last run failed.'
                    example: null
                  next_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Next scheduled materialisation, in ISO 8601.'
                    example: '2026-07-01T00:00:00+00:00'
                  last_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last materialisation timestamp, in ISO 8601.'
                    example: null
                  last_transaction_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the most recently materialised Tempus transaction.'
                    example: null
                  created_by_user_id:
                    type:
                      - string
                      - 'null'
                    description: 'User who created the template. Always null when created through the API key flow.'
                    example: null
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/recurring-transactions/{id}/resume':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusInternal
      summary: 'Resume a recurring transaction'
      operationId: postTempusRecurringTransactionResume
      description: |
        Sets the template status back to `active`, clears any failure reason, and re-anchors
        `next_run_at` to the next valid occurrence when it is null or in the past.
        Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: 'Unique recurring transaction template identifier.'
                    example: 550e8400-e29b-41d4-a716-446655440000
                  pbx_id:
                    type: string
                    format: uuid
                    description: 'PBX tenant the template belongs to.'
                    example: 550e8400-e29b-41d4-a716-446655440001
                  employee_id:
                    type: string
                    format: uuid
                    description: 'Tempus employee the materialised transactions are booked against.'
                    example: 550e8400-e29b-41d4-a716-446655440002
                  type:
                    type: string
                    description: 'Transaction type key.'
                    example: bonus
                  sub_type:
                    type:
                      - string
                      - 'null'
                    description: 'Optional sub-type key.'
                    example: annual
                  absence_type_id:
                    type:
                      - string
                      - 'null'
                    format: uuid
                    description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                    example: null
                  amount:
                    type: number
                    format: float
                    description: 'Amount applied on each run. Always greater than zero.'
                    example: 8
                  tr_type:
                    type: string
                    enum:
                      - credit
                      - debit
                    description: 'Whether each run credits or debits the balance.'
                    example: credit
                  note:
                    type:
                      - string
                      - 'null'
                    description: 'Free-text note carried onto each materialised transaction.'
                    example: 'Monthly meal allowance'
                  frequency:
                    type: string
                    enum:
                      - monthly_start
                      - yearly_start
                    description: 'When the template materialises a transaction.'
                    example: monthly_start
                  run_once:
                    type: boolean
                    description: 'When true the template runs a single time and then completes.'
                    example: false
                  status:
                    type: string
                    enum:
                      - active
                      - paused
                      - completed
                      - failed
                    description: 'Lifecycle status of the template.'
                    example: active
                  failure_reason:
                    type:
                      - string
                      - 'null'
                    description: 'Populated when the last run failed.'
                    example: null
                  next_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Next scheduled materialisation, in ISO 8601.'
                    example: '2026-07-01T00:00:00+00:00'
                  last_run_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    description: 'Last materialisation timestamp, in ISO 8601.'
                    example: null
                  last_transaction_id:
                    type:
                      - string
                      - 'null'
                    description: 'Identifier of the most recently materialised Tempus transaction.'
                    example: null
                  created_by_user_id:
                    type:
                      - string
                      - 'null'
                    description: 'User who created the template. Always null when created through the API key flow.'
                    example: null
                  created_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
                  updated_at:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: '2026-06-01T08:29:07+00:00'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/recurring-transactions/{id}/run-now':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusInternal
      summary: 'Run a recurring transaction now'
      operationId: postTempusRecurringTransactionRunNow
      description: |
        Materialises the template immediately (out of schedule). The template must be `active`.
        The HTTP response is `200` even when the individual run is skipped or fails; read
        `run.status` for the per-run outcome. Server-to-server only (PBX API key).
      security:
        -
          PbxApiKey: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: 'OK. The run was attempted; inspect `run.status` for the outcome.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  run:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      status:
                        type: string
                        enum:
                          - succeeded
                          - failed
                          - skipped
                      reason:
                        type:
                          - string
                          - 'null'
                      tempus_transaction_id:
                        type:
                          - string
                          - 'null'
                      ran_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                  template:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique recurring transaction template identifier.'
                        example: 550e8400-e29b-41d4-a716-446655440000
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'PBX tenant the template belongs to.'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      employee_id:
                        type: string
                        format: uuid
                        description: 'Tempus employee the materialised transactions are booked against.'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        description: 'Transaction type key.'
                        example: bonus
                      sub_type:
                        type:
                          - string
                          - 'null'
                        description: 'Optional sub-type key.'
                        example: annual
                      absence_type_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                        description: 'Linked absence type, when the transaction credits or debits an absence balance.'
                        example: null
                      amount:
                        type: number
                        format: float
                        description: 'Amount applied on each run. Always greater than zero.'
                        example: 8
                      tr_type:
                        type: string
                        enum:
                          - credit
                          - debit
                        description: 'Whether each run credits or debits the balance.'
                        example: credit
                      note:
                        type:
                          - string
                          - 'null'
                        description: 'Free-text note carried onto each materialised transaction.'
                        example: 'Monthly meal allowance'
                      frequency:
                        type: string
                        enum:
                          - monthly_start
                          - yearly_start
                        description: 'When the template materialises a transaction.'
                        example: monthly_start
                      run_once:
                        type: boolean
                        description: 'When true the template runs a single time and then completes.'
                        example: false
                      status:
                        type: string
                        enum:
                          - active
                          - paused
                          - completed
                          - failed
                        description: 'Lifecycle status of the template.'
                        example: active
                      failure_reason:
                        type:
                          - string
                          - 'null'
                        description: 'Populated when the last run failed.'
                        example: null
                      next_run_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Next scheduled materialisation, in ISO 8601.'
                        example: '2026-07-01T00:00:00+00:00'
                      last_run_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        description: 'Last materialisation timestamp, in ISO 8601.'
                        example: null
                      last_transaction_id:
                        type:
                          - string
                          - 'null'
                        description: 'Identifier of the most recently materialised Tempus transaction.'
                        example: null
                      created_by_user_id:
                        type:
                          - string
                          - 'null'
                        description: 'User who created the template. Always null when created through the API key flow.'
                        example: null
                      created_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2026-06-01T08:29:07+00:00'
                      updated_at:
                        type:
                          - string
                          - 'null'
                        format: date-time
                        example: '2026-06-01T08:29:07+00:00'
              example:
                run:
                  id: 550e8400-e29b-41d4-a716-446655440010
                  status: succeeded
                  reason: null
                  tempus_transaction_id: 550e8400-e29b-41d4-a716-446655440011
                  ran_at: '2026-06-30T09:15:00+00:00'
                template:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  status: active
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated principal is not allowed to manage recurring transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You are not authorised to manage recurring transactions.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: 'The recurring transaction is not active and cannot be run.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'This recurring transaction is not active.'
  '/{pbx_id}/users':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusEmployees
      summary: 'List Tempus employees for the tenant (user)'
      operationId: tempusListUsers
      description: |
        Returns a paginated list of Tempus employees (time-and-attendance records) belonging to the PBX tenant identified by `pbx_id`. Each item is serialized by the `TempusUserResource` and combines the `TempusEmployee` record with data resolved from its linked Voxbi user account and first telephony extension. The authenticated user must have an associated employee record and must belong to the requested PBX, otherwise the request is rejected with 403. Results may be filtered by department via `filter[group_id]` (matched through employee contracts) and are sorted by id by default.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[group_id]'
          in: query
          required: false
          description: |
            Comma-separated list of department (group) UUIDs to restrict results to. Employees are matched through their contracts' department assignment. Each value must be a valid UUID or the request is rejected with 422.
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          example: 20
      responses:
        200:
          description: 'Paginated list of Tempus employees.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusUser'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no associated employee record, or does not belong to the requested PBX tenant.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/absences':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusAbsences
      summary: 'List absences for the tenant (user)'
      operationId: tempusListAbsences
      description: |
        Returns a paginated list of absence transactions for the PBX tenant. Each item is a `TempusTransaction` ledger row of type absence, illness, special, or legal holiday.

        Only days actually taken are returned. Ledger rows that ADD days to a balance are excluded, because they are not time off: every credit row (`tr_type: credit`), including credits carrying no `sub_type` at all; the entitlement and carry-over sub-types (`computed_legal`, `computed_ph_on_day_off`, `computed_ph_on_same_day`, `computed_age`, `computed_experience`, `computed_company_day_off`, `computed_company_day_off_extra`, `legacy_custom`, `rollover`, `converted_balance`), which can be stored as debits and so are excluded by sub-type as well; `special_holiday` reversal rows; and `removal` give-backs. Granted days are reported by `GET /{pbx_id}/user/{employee_id}/calendar` instead. Passing one of the excluded values as `filter[sub_type]` therefore returns an empty list.

        By default the result covers every employee in the caller's active-contract company (a team holiday overview). `filter[employee_id]` and `filter[department_id]` narrow the set within that company. Filtering, sorting, and includes are powered by Spatie Query Builder.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[status]'
          in: query
          required: false
          description: 'Filter by transaction status (exact match).'
          schema:
            type: string
          example: accepted
        -
          name: 'filter[type]'
          in: query
          required: false
          description: 'Filter by transaction type (exact match).'
          schema:
            type: string
          example: legal
        -
          name: 'filter[sub_type]'
          in: query
          required: false
          description: |
            Filter by absence sub-type code (exact match). Must be a valid `TempusAbsenceType` code or the request is rejected with 422.
          schema:
            type: string
          example: paid_leave
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Return absences whose start date is on or after this date.'
          schema:
            type: string
            format: date
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Return absences whose end date is on or before this date.'
          schema:
            type: string
            format: date
          example: '2026-12-31'
        -
          name: 'filter[employee_id]'
          in: query
          required: false
          description: |
            Comma-separated list of employee UUIDs to restrict results to. Requires permission to view other employees' absences.
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[department_id]'
          in: query
          required: false
          description: |
            Comma-separated list of Tempus department UUIDs to restrict results to. Requires permission to view other employees' absences.
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: sort
          in: query
          required: false
          description: 'Sort field. Allowed: start_date, end_date, created_at. Prefix with - for descending.'
          schema:
            type: string
          example: '-start_date'
        -
          name: include
          in: query
          required: false
          description: 'Comma-separated related resources to include. Allowed: employee, requester.'
          schema:
            type: string
          example: employee
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 2000
            default: 15
          example: 15
      responses:
        200:
          description: 'Paginated list of absence transactions.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user has no associated employee record.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/absences':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusAbsences
      summary: 'List absences for a specific employee (user)'
      operationId: tempusListUserAbsences
      description: |
        Returns a paginated list of absence transactions for a single employee. Each item is a `TempusTransaction` ledger row of type absence, illness, special, or legal holiday.

        Only days actually taken are returned. Ledger rows that ADD days to a balance are excluded, because they are not time off: every credit row (`tr_type: credit`), including credits carrying no `sub_type` at all; the entitlement and carry-over sub-types (`computed_legal`, `computed_ph_on_day_off`, `computed_ph_on_same_day`, `computed_age`, `computed_experience`, `computed_company_day_off`, `computed_company_day_off_extra`, `legacy_custom`, `rollover`, `converted_balance`), which can be stored as debits and so are excluded by sub-type as well; `special_holiday` reversal rows; and `removal` give-backs. Granted days are reported by `GET /{pbx_id}/user/{employee_id}/calendar` instead. Passing one of the excluded values as `filter[sub_type]` therefore returns an empty list.

        The caller may always view their own absences; viewing another employee's absences requires the appropriate validator scope, otherwise the request is rejected with 403. Filtering and sorting are powered by Spatie Query Builder.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose absences are requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[status]'
          in: query
          required: false
          description: 'Filter by transaction status (exact match).'
          schema:
            type: string
          example: accepted
        -
          name: 'filter[type]'
          in: query
          required: false
          description: 'Filter by transaction type (exact match).'
          schema:
            type: string
          example: legal
        -
          name: 'filter[sub_type]'
          in: query
          required: false
          description: |
            Filter by absence sub-type code (exact match). Must be a valid `TempusAbsenceType` code or the request is rejected with 422.
          schema:
            type: string
          example: paid_leave
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Return absences whose start date is on or after this date.'
          schema:
            type: string
            format: date
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Return absences whose end date is on or before this date.'
          schema:
            type: string
            format: date
          example: '2026-12-31'
        -
          name: sort
          in: query
          required: false
          description: 'Sort field. Allowed: start_date, end_date, created_at. Prefix with - for descending.'
          schema:
            type: string
          example: '-start_date'
        -
          name: include
          in: query
          required: false
          description: 'Comma-separated related resources to include. Allowed: employee, requester.'
          schema:
            type: string
          example: employee
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 2000
            default: 15
          example: 15
      responses:
        200:
          description: 'Paginated list of absence transactions for the employee.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no associated employee record, or lacks permission to view the requested employee's absences.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/absence-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusAbsences
      summary: 'List pending absence requests for a PBX (user)'
      operationId: tempusListAbsenceRequests
      description: |
        Returns a paginated list of pending absence requests (debit transactions of type absence, legal holiday, illness or special) for the PBX. Callers without a validator scope only see their own requests unless they filter by group or employee. The response is a standard Laravel paginated collection.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[from]'
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 'Lower bound for the absence period.'
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 'Upper bound for the absence period.'
          example: '2026-01-31'
        -
          name: 'filter[status]'
          in: query
          required: false
          schema:
            type: string
          description: 'Comma-separated list of statuses to filter by.'
          example: pending
        -
          name: 'filter[department_id]'
          in: query
          required: false
          schema:
            type: string
          description: 'Comma-separated list of Tempus department ids; matches employees whose active contract is in one of these departments.'
          example: 550e8400-e29b-41d4-a716-446655440010
        -
          name: 'filter[employee_id]'
          in: query
          required: false
          schema:
            type: string
          description: 'Comma-separated list of employee IDs to filter by.'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: sort
          in: query
          required: false
          schema:
            type: string
          description: 'Sort field (start, end, start_date, end_date, created_at, status). Prefix with - for descending.'
          example: '-created_at'
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Page number.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 2000
          description: 'Items per page (default 15).'
          example: 15
      responses:
        200:
          description: 'Paginated list of absence requests.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user has no linked employee record or lacks permission to view the requested absences.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/absence-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusAbsences
      summary: 'List absence requests for a specific employee (user)'
      operationId: tempusListUserAbsenceRequests
      description: |
        Returns a paginated list of absence requests (debit transactions of type absence, legal holiday, illness or special) for the given employee. Callers may only view their own requests unless they hold a validator scope over the employee. The response is a standard Laravel paginated collection.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 'Lower bound for the absence period.'
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          schema:
            type: string
            format: date
          description: 'Upper bound for the absence period.'
          example: '2026-01-31'
        -
          name: 'filter[status]'
          in: query
          required: false
          schema:
            type: string
          description: 'Comma-separated list of statuses to filter by.'
          example: pending
        -
          name: sort
          in: query
          required: false
          schema:
            type: string
          description: 'Sort field (start, end, start_date, end_date, created_at, status). Prefix with - for descending.'
          example: '-created_at'
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Page number.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 2000
          description: 'Items per page (default 15).'
          example: 15
      responses:
        200:
          description: "Paginated list of the employee's absence requests."
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: "The authenticated user has no linked employee record or is not allowed to view this employee's absences."
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusAbsences
      summary: 'Create an absence request for a specific employee (user)'
      operationId: tempusCreateAbsenceRequest
      description: |
        Creates a new pending absence request for the employee. Requested time is expressed in seconds for the first and last day; weekends, public holidays, special holidays and dates already covered by other absences are skipped. If no working day remains after skipping, a 422 is returned.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - start
                - end
                - requested_time_first_day
                - requested_time_last_day
              properties:
                company_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: "Company the absence belongs to. Must exist for the PBX and the employee's contract."
                  example: 550e8400-e29b-41d4-a716-446655440020
                start:
                  type: string
                  format: date
                  description: 'First day of the absence.'
                  example: '2026-03-02'
                end:
                  type: string
                  format: date
                  description: 'Last day of the absence. Must be equal to or after start.'
                  example: '2026-03-06'
                requested_time_first_day:
                  type: integer
                  minimum: 1
                  maximum: 86400
                  description: |
                    Requested time on the first day, in seconds, expressed as a fraction of a nominal 8h day: send 28800 for a whole day and 14400 for a half day. The server scales that to the employee's own scheduled day, so a whole day for somebody contracted to 4h stores 14400 and a half of it stores 7200. Only the first and last day of a range can be a half day; on a single-day request this value is the one that applies. Days between the two ends take the employee's full scheduled seconds for that weekday.
                  example: 28800
                requested_time_last_day:
                  type: integer
                  minimum: 1
                  maximum: 86400
                  description: |
                    Requested time on the last day, in seconds, as a fraction of a nominal 8h day. Same scaling as `requested_time_first_day`. Ignored when start and end are the same date.
                  example: 28800
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 65535
                  description: 'Optional note attached to the request.'
                  example: 'Family trip'
                type:
                  type:
                    - string
                    - 'null'
                  enum:
                    - absence
                    - legal
                    - illness
                    - special
                  description: 'Absence type. Defaults to `legal` when omitted. `absence` is DEPRECATED — it was only ever a second name for `legal` and is stored as `legal`; responses always report `legal`.'
                  example: legal
                sub_type:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional sub type label.'
                  example: planned
      responses:
        201:
          description: 'The created absence request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusTransaction'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user has no linked employee record or is not allowed to create absences for this employee.'
        422:
          description: |
            Validation failed, or the requested period contains nothing bookable. The second case is returned when every date in the range is a weekend, a public holiday, a company special holiday, a day another absence already covers, or a day the employee's work shift schedules no hours for. It carries a bare `message` with no field-keyed `errors` object, so branch on whether `errors` is present.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                properties:
                  message:
                    type: string
                    example: 'No working days available in the selected date range.'
                  errors:
                    type: object
                    description: |
                      Present only for field validation failures, keyed by input field name. Absent when the period simply contains no bookable day.
                    additionalProperties:
                      type: array
                      items:
                        type: string
              examples:
                noWorkingDays:
                  summary: 'The period contains no bookable day'
                  value:
                    message: 'No working days available in the selected date range.'
                validationFailed:
                  summary: 'Field validation failed'
                  value:
                    message: 'The given data was invalid.'
                    errors:
                      end:
                        - 'The end field must be a date after or equal to start.'
  '/{pbx_id}/user/{employee_id}/absence-requests/{absence_request_id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    put:
      tags:
        - TempusAbsences
      summary: 'Update a pending absence request for an employee (user)'
      operationId: tempusUpdateAbsenceRequest
      description: |
        Updates a pending absence request. Only pending requests can be modified; any other status returns a 422. Dates and requested times default to the existing values when omitted. Sending a cancelling status only updates the status. The requested time is recalculated against weekends, public holidays, special holidays and overlapping absences.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: absence_request_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the absence request transaction.'
          example: 550e8400-e29b-41d4-a716-446655440030
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                company_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: "Company the absence belongs to. Must exist for the PBX and the employee's contract."
                  example: 550e8400-e29b-41d4-a716-446655440020
                start:
                  type: string
                  format: date
                  description: 'First day of the absence.'
                  example: '2026-03-02'
                end:
                  type: string
                  format: date
                  description: 'Last day of the absence. Must be equal to or after start.'
                  example: '2026-03-06'
                requested_time_first_day:
                  type: integer
                  minimum: 1
                  maximum: 86400
                  description: |
                    Requested time on the first day, in seconds, expressed as a fraction of a nominal 8h day: send 28800 for a whole day and 14400 for a half day. The server scales that to the employee's own scheduled day, so a whole day for somebody contracted to 4h stores 14400 and a half of it stores 7200. Days between the two ends take the employee's full scheduled seconds for that weekday. Omit to keep the value already stored on the request.
                  example: 28800
                requested_time_last_day:
                  type: integer
                  minimum: 1
                  maximum: 86400
                  description: |
                    Requested time on the last day, in seconds, as a fraction of a nominal 8h day. Same scaling as `requested_time_first_day`. Ignored when start and end are the same date. Omit to keep the value already stored on the request.
                  example: 28800
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 65535
                  description: 'Optional note attached to the request.'
                  example: 'Updated note'
                type:
                  type: string
                  enum:
                    - absence
                    - legal
                    - illness
                    - special
                  description: 'Absence type. `absence` is DEPRECATED — it was only ever a second name for `legal` and is stored as `legal`; responses always report `legal`.'
                  example: legal
                sub_type:
                  type:
                    - string
                    - 'null'
                  maxLength: 255
                  description: 'Optional sub type label.'
                  example: planned
                status:
                  type: string
                  enum:
                    - cancelled
                    - canceled
                  description: 'Set to a cancelling status to cancel the request without changing other fields.'
                  example: cancelled
      responses:
        200:
          description: 'The updated absence request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusTransaction'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user has no linked employee record or is not allowed to update this request.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/absence-requests/{absence_request_id}/cancel':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusAbsences
      summary: 'Cancel an absence request, or take back its cancellation (user)'
      operationId: tempusCancelAbsenceRequest
      description: |
        The single endpoint an employee uses to undo an absence, at whatever stage it
        has reached. What it does depends on the current status of the request:

        | Current status | What happens | Response `status` |
        |---|---|---|
        | `pending` | Cancelled outright. Pending approvals are deleted and no validator is asked. | `canceled` |
        | `accepted` (internally `approved`) | Cannot be deleted directly. A **removal request** (a credit transaction, `sub_type: removal`) is created and the original moves to `pending_removal`; a validator must approve the removal before the days come back. | `pending` (of the new removal row) |
        | `pending_removal` | The open removal is **revoked**: it is cancelled and the absence returns to `accepted`. The days stay booked, exactly as if a validator had rejected the removal. | `accepted` |
        | anything else (`rejected`, `removed`, `canceled`) | Nothing. `400`. | n/a |

        ### Taking back a cancellation

        The `pending_removal` row is what makes this endpoint reversible. An employee
        who asked for an approved holiday to be given back - either through this
        endpoint or through `POST /{pbx_id}/user/{employee_id}/absence-removal-requests` -
        can change their mind for as long as no validator has ruled, and keep the days.

        You may address that revocation with **either id**:

        - the **original absence** id (status `pending_removal`) - the row the employee
          sees in their calendar, and the id a client normally holds; or
        - the **removal request** id (status `pending`, `sub_type: removal`) - the
          credit row created when the removal was opened.

        Both land on the same state and both answer with the **restored original
        absence**, never with the withdrawn credit row. Revoking also deletes the
        removal's pending approvals, so no validator is left holding a decision that no
        longer matters.

        Revocation is not one-way: once the absence is back to `accepted`, calling this
        endpoint again simply opens a fresh removal request.

        ### Emails

        A withdrawal the employee performs themselves is confirmed by email to the
        employee the absence belongs to, and to whoever filed it when that is someone
        else. Two different messages are sent:

        - **request cancelled** - a `pending` request was withdrawn;
        - **cancellation withdrawn** - a `pending_removal` was revoked and the days
          stay booked.

        Opening a removal (the `accepted` branch) sends no such confirmation: nothing
        has been withdrawn yet, and the validators are notified instead.

        ### Authorization

        Owner-based: only the employee the request belongs to may cancel it, regardless
        of who created it on their behalf. The request is resolved by its own id, so
        the `{employee_id}` path segment is **not** used for authorization - a request
        that genuinely does not exist returns `404`, one that exists but is not the
        caller's returns `403`.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the employee (path segment only; not used for authorization - the request is resolved by its own id and cancel is owner-based).
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: absence_request_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the absence request transaction. To revoke a cancellation this may be either the original absence (status `pending_removal`) or its pending removal request (`sub_type: removal`) - both are accepted.
          example: 550e8400-e29b-41d4-a716-446655440030
      requestBody:
        required: false
        description: |
          No body. The outcome is decided entirely by the current status of the addressed request; send an empty body or omit it.
      responses:
        200:
          description: |
            The affected absence request, serialized by the V1 transaction resource
            (unwrapped - the object is the response body, there is no `data` envelope).

            Which row you get back depends on the branch taken: the cancelled request,
            the newly created pending removal, or the restored original absence. Switch
            on `status` and `sub_type` rather than assuming.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusTransaction'
              examples:
                pendingCancelled:
                  summary: 'A pending request was withdrawn'
                  description: |
                    Nothing was booked yet, so the request is simply cancelled and its pending approvals are dropped.
                  value:
                    id: 550e8400-e29b-41d4-a716-446655440030
                    mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                    employee_id: 550e8400-e29b-41d4-a716-446655440001
                    requester_id: 550e8400-e29b-41d4-a716-446655440001
                    creator_id: 550e8400-e29b-41d4-a716-446655440001
                    ext_id: EXT-10293
                    company_id: 550e8400-e29b-41d4-a716-446655440003
                    absence_request_id: 550e8400-e29b-41d4-a716-446655440030
                    holiday_id: null
                    status: canceled
                    type: legal
                    sub_type: null
                    start: '2026-09-14T00:00:00+00:00'
                    end: '2026-09-15T00:00:00+00:00'
                    requested_time:
                      '2026-09-14': 28800
                      '2026-09-15': 28800
                    working_days: 2
                    total_seconds: 57600
                    workshift_seconds_per_day: 28800
                    is_half_day: false
                    starts_half_day: false
                    ends_half_day: false
                    start_time: null
                    end_time: null
                    working_day_details:
                      -
                        date: '2026-09-14'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                      -
                        date: '2026-09-15'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                    comment: 'Changed my plans.'
                    accepted_by: {}
                    created: '2026-09-01T10:00:00+00:00'
                    modified: '2026-09-02T08:15:00+00:00'
                removalOpened:
                  summary: 'An approved absence opened a removal request'
                  description: |
                    The response is the NEW credit row (`sub_type: removal`), not the original. The original is now `pending_removal` and the days stay booked until a validator approves this removal.
                  value:
                    id: 550e8400-e29b-41d4-a716-446655440077
                    mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                    employee_id: 550e8400-e29b-41d4-a716-446655440001
                    requester_id: 550e8400-e29b-41d4-a716-446655440001
                    creator_id: 550e8400-e29b-41d4-a716-446655440001
                    ext_id: EXT-10293
                    company_id: 550e8400-e29b-41d4-a716-446655440003
                    absence_request_id: 550e8400-e29b-41d4-a716-446655440077
                    holiday_id: null
                    status: pending
                    type: legal
                    sub_type: removal
                    start: '2026-08-03T00:00:00+00:00'
                    end: '2026-08-05T00:00:00+00:00'
                    requested_time:
                      '2026-08-03': 28800
                      '2026-08-04': 28800
                      '2026-08-05': 28800
                    working_days: 3
                    total_seconds: 86400
                    workshift_seconds_per_day: 28800
                    is_half_day: false
                    starts_half_day: false
                    ends_half_day: false
                    start_time: null
                    end_time: null
                    working_day_details:
                      -
                        date: '2026-08-03'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                      -
                        date: '2026-08-04'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                      -
                        date: '2026-08-05'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                    comment: 'Family event, returning Thursday.'
                    accepted_by:
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440004
                        status: pending
                    created: '2026-08-06T09:00:00+00:00'
                    modified: '2026-08-06T09:00:00+00:00'
                removalRevoked:
                  summary: 'A pending removal was revoked - the days stay booked'
                  description: |
                    Returned whether you addressed the original absence or its removal row. The removal is now `canceled` and this absence is `accepted` again.
                  value:
                    id: 550e8400-e29b-41d4-a716-446655440030
                    mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                    employee_id: 550e8400-e29b-41d4-a716-446655440001
                    requester_id: 550e8400-e29b-41d4-a716-446655440001
                    creator_id: 550e8400-e29b-41d4-a716-446655440001
                    ext_id: EXT-10293
                    company_id: 550e8400-e29b-41d4-a716-446655440003
                    absence_request_id: 550e8400-e29b-41d4-a716-446655440030
                    holiday_id: null
                    status: accepted
                    type: legal
                    sub_type: null
                    start: '2026-08-03T00:00:00+00:00'
                    end: '2026-08-05T00:00:00+00:00'
                    requested_time:
                      '2026-08-03': 28800
                      '2026-08-04': 28800
                      '2026-08-05': 28800
                    working_days: 3
                    total_seconds: 86400
                    workshift_seconds_per_day: 28800
                    is_half_day: false
                    starts_half_day: false
                    ends_half_day: false
                    start_time: null
                    end_time: null
                    working_day_details:
                      -
                        date: '2026-08-03'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                      -
                        date: '2026-08-04'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                      -
                        date: '2026-08-05'
                        seconds: 28800
                        is_half_day: false
                        start_time: null
                        end_time: null
                    comment: 'Family event, returning Thursday.'
                    accepted_by:
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440004
                        status: accepted
                    created: '2026-07-28T10:00:00+00:00'
                    modified: '2026-08-06T11:42:00+00:00'
        400:
          description: |
            The request is in a status that cannot be cancelled - `rejected`, `removed` or already `canceled`. Only `pending`, `accepted` and `pending_removal` rows can be acted on.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Only pending, approved or pending-removal absence requests can be cancelled.'
              example:
                message: 'Only pending, approved or pending-removal absence requests can be cancelled.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The request exists but does not belong to the authenticated user (only its owner may cancel it).'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/user/{employee_id}/absence-removal-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusAbsences
      summary: 'Request removal of an approved legal holiday absence (user)'
      operationId: tempusCreateAbsenceRemovalRequest
      description: |
        Creates a pending removal request to credit back an approved legal holiday
        absence. The referenced absence must be an approved legal holiday debit
        transaction with no pending removal already in flight. The original absence
        moves to a pending-removal status and the created credit transaction must be
        validated.

        **This is reversible.** For as long as no validator has ruled, the employee can
        take the removal back and keep the days, via
        `POST /{pbx_id}/user/{employee_id}/absence-requests/{absence_request_id}/cancel`.
        That endpoint accepts either the original absence's id (now `pending_removal`)
        or the `id` returned here, and restores the absence to `accepted`.

        The same cancel endpoint is also the shorter way to *open* a removal: calling
        it on an approved absence creates exactly the row this endpoint does. Use this
        endpoint when you want to attach a `comment` to the removal.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - absence_id
              properties:
                absence_id:
                  type: string
                  format: uuid
                  description: 'UUID of the approved legal holiday absence to remove.'
                  example: 550e8400-e29b-41d4-a716-446655440030
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 65535
                  description: 'Optional note attached to the removal request.'
                  example: 'Cancelling planned leave'
      responses:
        201:
          description: 'The created pending removal request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusTransaction'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user has no linked employee record or is not allowed to create removal requests for this employee.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/absence-requests/{absence_request_id}/validations':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusAbsences
      summary: 'List validations for an absence request (user)'
      operationId: tempusListAbsenceRequestValidations
      description: |
        Returns the paginated list of validation (approval) records for a single
        absence request. Each record is one validator's decision on the request:
        pending, accepted, or rejected, with an optional comment. The authenticated
        user must be allowed to view approvals for the request.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: absence_request_id
          in: path
          required: true
          description: 'UUID of the absence request (Tempus transaction).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of records per page (maximum 100, defaults to 15).'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 15
      responses:
        200:
          description: 'Paginated list of absence request validations.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransactionApproval'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user is not allowed to view approvals for this absence request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusAbsences
      summary: 'Submit a validation decision for an absence request (user)'
      operationId: tempusCreateAbsenceRequestValidation
      description: |
        Records the authenticated validator's decision (accepted or rejected) on an
        absence request. The user must have an employee record and be allowed to
        create an approval for the request. If the validator already submitted a
        final decision, the request is rejected with a conflict.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: absence_request_id
          in: path
          required: true
          description: 'UUID of the absence request (Tempus transaction).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    - accepted
                    - rejected
                  description: 'The validation decision for the absence request.'
                  example: accepted
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free-form note explaining the decision.'
                  example: 'Approved, please coordinate handover with the team.'
            example:
              status: accepted
              comment: 'Approved, please coordinate handover with the team.'
      responses:
        201:
          description: 'The validation decision was recorded.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                properties:
                  message:
                    type: string
                    example: 'Absence request validation created.'
        400:
          description: 'The absence request is no longer in a pending state and cannot be validated.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The absence request is not pending.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no employee record or is not allowed to create
            an approval for this absence request.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'An employee record is required to perform this action.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: 'A final validation decision has already been submitted by this validator.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This absence request has already been validated.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/home-office-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusHomeOffice
      summary: 'List home office requests (tenant-wide, validator-scoped)'
      operationId: tempusListHomeOfficeRequests
      description: |
        Return a paginated list of home office requests (Tempus transactions of type
        `home_office`) across the PBX. The acting user must have a linked Tempus
        employee record. When the user is not a validator with home office scope and
        no `filter[department_id]` or `filter[employee_id]` is supplied, results are
        limited to the acting user's own requests. Validators may filter by
        `employee_id` or `department_id` within their scope.

        For a single employee's requests use
        `GET /{pbx_id}/user/{employee_id}/home-office-requests` instead.

        Each item is serialized by the V1 transaction resource. The list is wrapped in
        the standard Laravel pagination envelope (`data`, `links`, `meta`).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the PBX tenant'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Start of the date window the request period must overlap.'
          schema:
            type: string
            format: date
            example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'End of the date window the request period must overlap.'
          schema:
            type: string
            format: date
            example: '2024-03-31'
        -
          name: 'filter[status]'
          in: query
          required: false
          description: |
            Comma-separated list of statuses to filter by. Accepts API aliases:
            `accepted` maps to the internal `approved`, `canceled` maps to the
            internal `cancelled`.
          schema:
            type: string
            example: 'accepted,pending'
        -
          name: 'filter[department_id]'
          in: query
          required: false
          description: 'Comma-separated list of Tempus department ids; matches employees whose active contract is in one of these departments.'
          schema:
            type: string
            example: 550e8400-e29b-41d4-a716-446655440010
        -
          name: 'filter[employee_id]'
          in: query
          required: false
          description: 'Comma-separated list of employee identifiers to filter by.'
          schema:
            type: string
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: sort
          in: query
          required: false
          description: |
            Sort field. Supports `start`, `end`, `start_date`, `end_date`,
            `created_at`, `status`. Prefix with `-` for descending order.
          schema:
            type: string
            example: '-start_date'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
            example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            example: 15
      responses:
        200:
          description: 'Paginated list of home office requests'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The acting user has no linked Tempus employee record, or the policy
            `viewAny` check denied access.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/home-office-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusHomeOffice
      summary: "List a specific employee's home office requests"
      operationId: tempusListUserHomeOfficeRequests
      description: |
        Return a paginated list of home office requests (Tempus transactions of type
        `home_office`) for the employee identified by the `employee_id` path
        parameter. The caller may view their own requests, or - when they are a
        validator - another employee's; otherwise `403` is returned. Results are
        always scoped to the path employee (there is no `ext_id` filter here; use
        `GET /{pbx_id}/home-office-requests` for the tenant-wide, filterable list).

        Each item is serialized by the V1 transaction resource. The list is wrapped in
        the standard Laravel pagination envelope (`data`, `links`, `meta`).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the PBX tenant'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'Identifier of the employee whose home office requests are listed'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Start of the date window the request period must overlap.'
          schema:
            type: string
            format: date
            example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'End of the date window the request period must overlap.'
          schema:
            type: string
            format: date
            example: '2024-03-31'
        -
          name: 'filter[status]'
          in: query
          required: false
          description: |
            Comma-separated list of statuses to filter by. Accepts API aliases:
            `accepted` maps to the internal `approved`, `canceled` maps to the
            internal `cancelled`.
          schema:
            type: string
            example: 'accepted,pending'
        -
          name: sort
          in: query
          required: false
          description: |
            Sort field. Supports `start`, `end`, `start_date`, `end_date`,
            `created_at`, `status`. Prefix with `-` for descending order.
          schema:
            type: string
            example: '-start_date'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
            example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            example: 15
      responses:
        200:
          description: 'Paginated list of home office requests'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The acting user has no linked Tempus employee record, or is neither the
            target employee nor a validator, so may not view this employee's requests.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusHomeOffice
      summary: 'Request home office days for an employee (user)'
      operationId: tempusCreateHomeOfficeRequest
      description: |
        Request one or more home office days for the given employee. Each date in
        `dates` becomes its own pending Tempus transaction of type `home_office` (a
        per-day ledger row); all rows created by one call share a `request_group_id`.
        Each day debits a full working day (28800 seconds). Approval records are
        generated automatically.

        Tenant (`pbx_id`), owning employee, requester, type, status and amounts are
        set server-side and must not be sent in the body. Dates that are public
        holidays, already booked as home office, or overlapping an absence are
        rejected with `422` and an `invalid_dates` payload.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the PBX tenant'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'Identifier of the employee the request is created for'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - dates
              properties:
                dates:
                  type: array
                  minItems: 1
                  maxItems: 100
                  description: |
                    Home office days to request, each `YYYY-MM-DD`. Every date must be
                    today or later and within six months, and be unique. Each date
                    becomes its own pending transaction.
                  items:
                    type: string
                    format: date
                    example: '2024-03-04'
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                  description: 'Optional free-form note attached to every created day-row.'
                  example: 'Working from home.'
            example:
              dates:
                - '2024-03-04'
                - '2024-03-06'
              comment: 'Working from home.'
      responses:
        201:
          description: 'The created home office day-rows, one per requested date. Wrapped in a `data` array.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The acting user has no linked Tempus employee record, or the policy
            `create` check denied access.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/home-office-requests/cancel':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusHomeOffice
      summary: 'Withdraw home office days, or take back their cancellation (user)'
      operationId: tempusCancelHomeOfficeRequests
      description: |
        Withdraw one or more home office day-rows (Tempus transactions of type
        `home_office`) by id. Home office is stored one row per day, so this endpoint
        is a bulk operation: it is best-effort and decides per row from that row's
        current status.

        | Current status | What happens | Reported under |
        |---|---|---|
        | `pending` | Cancelled directly; its pending approvals are deleted. | `cancelled` |
        | `accepted` (internally `approved`) | A **removal request** (credit row, `sub_type: removal`) is created and the day moves to `pending_removal`; a validator must approve it. | `cancelled` (the new removal row) |
        | `pending_removal` | The open removal is **revoked** and the day returns to `accepted` - the employee taking back their own cancellation. | `cancelled` (the restored day) |
        | `removed`, `canceled`, `rejected`, or an id that is not one of this employee's home office days | Nothing. | `skipped` |

        The call always returns `200`: valid days are acted on even when others are
        skipped, and every id you sent is accounted for in exactly one of the two
        lists.

        ### Taking back a cancellation

        A day whose removal is still waiting for validation can be given back to the
        employee for as long as no validator has ruled. Pass **either id**:

        - the **original day** (status `pending_removal`), or
        - its **removal row** (status `pending`, `sub_type: removal`).

        Both revoke the removal and both report the **restored original day** in
        `cancelled` - so an entry in `cancelled` is not always the row whose id you
        sent. Match on the returned objects, not positionally against your input.

        Sending both ids of the same pair in one call is safe: the pair is revoked
        once, the original appears in `cancelled`, and the removal row - already
        cancelled by then - is reported in `skipped` as `already_cancelled`.

        ### Emails

        Withdrawing a `pending` day, and revoking a `pending_removal`, each confirm by
        email to the employee (and to whoever filed the day, when that is someone
        else). Opening a removal on an `accepted` day sends no confirmation - nothing
        has been withdrawn yet, and the validators are notified instead.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the PBX tenant'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'Identifier of the employee who owns the requests'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  minItems: 1
                  maxItems: 100
                  description: |
                    Identifiers of the home office day-rows to act on. Each must be an
                    existing `home_office` transaction in this PBX belonging to this
                    employee. To revoke a cancellation, pass either the original day or
                    its pending removal row.
                  items:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440030
            examples:
              withdrawPendingDays:
                summary: 'Withdraw two days that are still waiting for validation'
                value:
                  ids:
                    - 550e8400-e29b-41d4-a716-446655440030
                    - 550e8400-e29b-41d4-a716-446655440031
              revokeByOriginalId:
                summary: 'Take back the cancellation of a day whose removal is still pending'
                value:
                  ids:
                    - 550e8400-e29b-41d4-a716-446655440040
              mixedBatch:
                summary: 'A mixed batch - one withdrawn, one revoked, one already removed'
                value:
                  ids:
                    - 550e8400-e29b-41d4-a716-446655440030
                    - 550e8400-e29b-41d4-a716-446655440040
                    - 550e8400-e29b-41d4-a716-446655440050
      responses:
        200:
          description: |
            The outcome of the call. `cancelled` holds the affected day-rows in their
            new state - cancelled outright, moved to `pending_removal`, or restored to
            `accepted` after a revocation. `skipped` lists the ids that were not acted
            on, each with a machine `reason` and a human `message`.
          content:
            application/json:
              schema:
                type: object
                required:
                  - cancelled
                  - skipped
                properties:
                  cancelled:
                    type: array
                    description: |
                      The resulting day-rows, in their new state. Not necessarily the rows whose ids you sent: revoking by a removal row's id reports the restored original instead.
                    items:
                      $ref: '#/components/schemas/TempusTransaction'
                  skipped:
                    type: array
                    description: 'Requested ids that were not acted on, each with the reason why.'
                    items:
                      type: object
                      required:
                        - id
                        - status
                        - reason
                        - message
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: 'The requested day-row id.'
                          example: 550e8400-e29b-41d4-a716-446655440050
                        status:
                          type:
                            - string
                            - 'null'
                          description: |
                            Current internal status of the row, or null when the id did not resolve to one of this employee's home office days.
                          enum:
                            - removed
                            - cancelled
                            - rejected
                            - null
                          example: removed
                        reason:
                          type: string
                          description: 'Machine-readable skip reason.'
                          enum:
                            - already_removed
                            - already_cancelled
                            - not_cancellable
                            - not_found
                          example: already_removed
                        message:
                          type: string
                          description: 'Human-readable explanation, suitable for display.'
                          example: 'This date has already been removed.'
              examples:
                pendingWithdrawn:
                  summary: 'A pending day was withdrawn'
                  value:
                    cancelled:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440030
                        mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                        employee_id: 550e8400-e29b-41d4-a716-446655440001
                        requester_id: 550e8400-e29b-41d4-a716-446655440001
                        creator_id: 550e8400-e29b-41d4-a716-446655440001
                        ext_id: EXT-10293
                        company_id: 550e8400-e29b-41d4-a716-446655440003
                        absence_request_id: 550e8400-e29b-41d4-a716-446655440030
                        holiday_id: null
                        status: canceled
                        type: home_office
                        sub_type: null
                        start: '2026-09-14T00:00:00+00:00'
                        end: '2026-09-14T00:00:00+00:00'
                        requested_time:
                          '2026-09-14': 28800
                        working_days: 1
                        total_seconds: 28800
                        workshift_seconds_per_day: 28800
                        is_half_day: false
                        starts_half_day: false
                        ends_half_day: false
                        start_time: null
                        end_time: null
                        working_day_details:
                          -
                            date: '2026-09-14'
                            seconds: 28800
                            is_half_day: false
                            start_time: null
                            end_time: null
                        comment: null
                        accepted_by: {}
                        created: '2026-09-01T10:00:00+00:00'
                        modified: '2026-09-02T08:15:00+00:00'
                    skipped: {}
                removalRevoked:
                  summary: 'A pending removal was revoked - the day stays booked'
                  description: |
                    Returned whether you addressed the original day or its removal row. `status` is back to `accepted`.
                  value:
                    cancelled:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440040
                        mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                        employee_id: 550e8400-e29b-41d4-a716-446655440001
                        requester_id: 550e8400-e29b-41d4-a716-446655440001
                        creator_id: 550e8400-e29b-41d4-a716-446655440001
                        ext_id: EXT-10293
                        company_id: 550e8400-e29b-41d4-a716-446655440003
                        absence_request_id: 550e8400-e29b-41d4-a716-446655440040
                        holiday_id: null
                        status: accepted
                        type: home_office
                        sub_type: null
                        start: '2026-08-10T00:00:00+00:00'
                        end: '2026-08-10T00:00:00+00:00'
                        requested_time:
                          '2026-08-10': 28800
                        working_days: 1
                        total_seconds: 28800
                        workshift_seconds_per_day: 28800
                        is_half_day: false
                        starts_half_day: false
                        ends_half_day: false
                        start_time: null
                        end_time: null
                        working_day_details:
                          -
                            date: '2026-08-10'
                            seconds: 28800
                            is_half_day: false
                            start_time: null
                            end_time: null
                        comment: null
                        accepted_by:
                          -
                            employee_id: 550e8400-e29b-41d4-a716-446655440004
                            status: accepted
                        created: '2026-07-30T10:00:00+00:00'
                        modified: '2026-08-06T11:42:00+00:00'
                    skipped: {}
                mixedOutcome:
                  summary: 'One withdrawn, one revoked, one skipped'
                  description: |
                    The three ids from the `mixedBatch` request body. Note the shapes differ per row - switch on `status` and `sub_type`.
                  value:
                    cancelled:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440030
                        status: canceled
                        type: home_office
                        sub_type: null
                        employee_id: 550e8400-e29b-41d4-a716-446655440001
                        start: '2026-09-14T00:00:00+00:00'
                        end: '2026-09-14T00:00:00+00:00'
                        working_days: 1
                        total_seconds: 28800
                      -
                        id: 550e8400-e29b-41d4-a716-446655440040
                        status: accepted
                        type: home_office
                        sub_type: null
                        employee_id: 550e8400-e29b-41d4-a716-446655440001
                        start: '2026-08-10T00:00:00+00:00'
                        end: '2026-08-10T00:00:00+00:00'
                        working_days: 1
                        total_seconds: 28800
                    skipped:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440050
                        status: removed
                        reason: already_removed
                        message: 'This date has already been removed.'
                allSkipped:
                  summary: 'Nothing could be acted on'
                  value:
                    cancelled: {}
                    skipped:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440060
                        status: null
                        reason: not_found
                        message: 'This home office day could not be found for this employee.'
                      -
                        id: 550e8400-e29b-41d4-a716-446655440061
                        status: rejected
                        reason: not_cancellable
                        message: 'This date cannot be cancelled.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The policy `create` check denied access for this employee.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/home-office-requests/{home_office_request_id}/validations':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusHomeOffice
      summary: 'List validations for a home office request (user)'
      operationId: tempusListHomeOfficeRequestValidations
      description: |
        Returns the paginated list of validation (approval) records for a single
        home office request. The home office request is resolved from the underlying
        Tempus transaction, scoped to the authenticated tenant. Each record
        represents one validator's decision on the request.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: home_office_request_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the home office request (Tempus transaction)'
          example: 550e8400-e29b-41d4-a716-446655440030
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Page number to retrieve.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: 'Number of records per page (defaults to 15).'
          example: 15
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTransactionApproval'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440040
                    mxvp_user_id: 550e8400-e29b-41d4-a716-446655440000
                    absence_request_id: 550e8400-e29b-41d4-a716-446655440030
                    ext_id: '201'
                    validator:
                      id: 550e8400-e29b-41d4-a716-446655440003
                      name: 'Jane Smith'
                    status: accepted
                    comment: 'Approved as requested.'
                    create_time: '2024-03-01T08:29:07+00:00'
                    modified: '2024-03-01T09:15:42+00:00'
                    holiday_id: null
                links:
                  first: 'https://cockpit.voxbi.com/tempus/api/v1/resources?page=1'
                  last: 'https://cockpit.voxbi.com/tempus/api/v1/resources?page=1'
                  prev: null
                  next: null
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  path: 'https://cockpit.voxbi.com/tempus/api/v1/resources'
                  per_page: 15
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Forbidden: the authenticated user is not allowed to view validations for this home office request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusHomeOffice
      summary: 'Submit a validation decision for a home office request (user)'
      operationId: tempusCreateHomeOfficeRequestValidation
      description: |
        Records the authenticated validator's decision (accepted or rejected) on a
        home office request and processes the approval against the underlying Tempus
        transaction. The authenticated user must have an associated employee record.
        A validator may only submit one decision per request.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: home_office_request_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the home office request (Tempus transaction)'
          example: 550e8400-e29b-41d4-a716-446655440030
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    - accepted
                    - rejected
                  description: 'The validation decision for the home office request.'
                  example: accepted
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free-form note explaining the decision.'
                  example: 'Approved as requested.'
            example:
              status: accepted
              comment: 'Approved as requested.'
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'Validation created successfully.'
        400:
          description: 'Bad Request: the home office request is not in pending status and cannot be validated.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'The request is not pending and cannot be validated.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Forbidden: the authenticated user is not allowed to validate this request, or has no associated employee record.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: 'Conflict: the authenticated validator has already submitted a decision for this request.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: 'You have already validated this request.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/home-office-requests/validations':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusHomeOffice
      summary: 'Validate several home office day-rows at once'
      operationId: tempusBulkValidateHomeOfficeRequests
      description: |
        Apply a single decision (`accepted` or `rejected`) to several home office
        day-rows in one call, for example a whole request group or week. The acting
        user must be a validator with home office scope over the affected employees.

        Rows that are not `pending`, or that the acting validator has already decided,
        are skipped rather than failing the batch. The response reports how many rows
        were processed and skipped.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the PBX tenant'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
                - status
              properties:
                ids:
                  type: array
                  minItems: 1
                  maxItems: 100
                  description: 'Identifiers of the home office day-rows to validate.'
                  items:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440030
                status:
                  type: string
                  enum:
                    - accepted
                    - rejected
                  description: 'The decision to apply to every listed row.'
                  example: accepted
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional note stored on each created approval.'
                  example: 'Approved for the whole week.'
            example:
              ids:
                - 550e8400-e29b-41d4-a716-446655440030
                - 550e8400-e29b-41d4-a716-446655440031
              status: accepted
      responses:
        200:
          description: 'The decision was applied. Reports processed and skipped counts.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - processed
                  - skipped
                properties:
                  message:
                    type: string
                    example: 'Validation completed.'
                  processed:
                    type: integer
                    description: 'Number of rows a decision was recorded for.'
                    example: 2
                  skipped:
                    type: integer
                    description: 'Rows skipped (not pending, or already decided by this validator).'
                    example: 0
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The acting user is not a validator for one of the listed rows.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/home-office-calendars':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusHomeOffice
      summary: 'List home office calendars across employees (user)'
      operationId: tempusListHomeOfficeCalendars
      description: |
        Returns virtual home office calendar entries aggregated from `home_office`
        transactions across the tenant. Each entry groups the pending, approved, and
        removed home-office days for one employee, company, and calendar year.

        When the caller has permission to view other employees' home office
        (resolved from the validator scope), entries for the caller's company are
        returned; without a group filter the result is scoped to the caller's
        company. Otherwise only the caller's own entries are returned. The response
        is a plain list under `data` and is not paginated, even though `page` and
        `per_page` are accepted as filters.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[year]'
          in: query
          required: false
          schema:
            type: integer
            minimum: 2000
            maximum: 2100
          description: 'Restrict the calendars to a single calendar year.'
          example: 2026
        -
          name: 'filter[group_id]'
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: 'Restrict the calendars to employees in a specific department group.'
          example: 550e8400-e29b-41d4-a716-446655440010
        -
          name: include
          in: query
          required: false
          schema:
            type: string
            enum:
              - user
          description: 'When set to `user`, embeds the linked Voxbi user summary on each entry.'
          example: user
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Accepted for compatibility; the response is not paginated.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: 'Accepted for compatibility; the response is not paginated.'
          example: 15
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusHomeOfficeCalendar'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user does not belong to the requested PBX
            tenant.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/home-office-calendars':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusHomeOffice
      summary: 'List home office calendars for one employee (user)'
      operationId: tempusListUserHomeOfficeCalendars
      description: |
        Returns the virtual home office calendar entries for a single employee,
        aggregated from that employee's `home_office` transactions and grouped by
        company and calendar year. The response is a plain list under `data` and is
        not paginated, even though `page` and `per_page` are accepted as filters.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the Tempus employee whose calendars are returned.'
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[year]'
          in: query
          required: false
          schema:
            type: integer
            minimum: 2000
            maximum: 2100
          description: 'Restrict the calendars to a single calendar year.'
          example: 2026
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: 'Accepted for compatibility; the response is not paginated.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: 'Accepted for compatibility; the response is not paginated.'
          example: 15
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusHomeOfficeCalendar'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/calendar/absence':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCalendar
      summary: 'Company absence calendar'
      operationId: tempusAbsenceCalendar
      description: |
        Lightweight absence calendar for the caller's company: every colleague's absence, illness, special and legal-holiday bookings in the `pending`, `approved` and `pending_removal` states. Any employee in the company may read it (a team availability view); this is intentionally not scoped to the caller's own records and carries only the fields a calendar needs - full request detail lives on the `absence-requests` endpoints. The response is a flat array, not wrapped in a `data` envelope and not paginated. Cancellation-in-progress rows appear once (the original, as `pending_removal`); the internal removal credit is omitted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[department_id]'
          in: query
          required: false
          description: "Narrow to one or more departments (comma-separated), by the employee's active contract. Omit for the whole company."
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440042
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Only events overlapping on or after this date (`Y-m-d`).'
          schema:
            type: string
            format: date
          example: '2026-07-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Only events overlapping on or before this date (`Y-m-d`).'
          schema:
            type: string
            format: date
          example: '2026-07-31'
      responses:
        200:
          description: 'The company absence calendar. Flat array, not wrapped in data, not paginated.'
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                      example: 550e8400-e29b-41d4-a716-446655440030
                    employee_id:
                      type: string
                      format: uuid
                      example: 550e8400-e29b-41d4-a716-446655440001
                    employee_name:
                      type:
                        - string
                        - 'null'
                      example: 'Jane Smith'
                    department_id:
                      type:
                        - string
                        - 'null'
                      format: uuid
                      description: "Department of the employee's active contract; null when none."
                      example: 550e8400-e29b-41d4-a716-446655440042
                    type:
                      type: string
                      enum:
                        - absence
                        - illness
                        - special
                        - legal
                      example: absence
                    sub_type:
                      type:
                        - string
                        - 'null'
                      description: 'Absence sub-type where applicable (e.g. special_holiday).'
                      example: null
                    status:
                      type: string
                      enum:
                        - pending
                        - approved
                        - pending_removal
                      example: approved
                    start:
                      type: string
                      format: date
                      example: '2026-07-07'
                    end:
                      type: string
                      format: date
                      example: '2026-07-09'
                    total_seconds:
                      type: integer
                      description: 'Total booked time across all days, in seconds.'
                      example: 86400
                    days:
                      type: array
                      description: |
                        Every entry of the booking's raw per-day map, in stored order. Rows written before that map held working days only carry a `0` for each weekend and public holiday inside the range, so this array can be longer than the days actually taken. `working_day_details` below is the same breakdown with those dropped and the half-day hours resolved; both are returned, and this one is unchanged.
                      items:
                        type: object
                        properties:
                          date:
                            type: string
                            format: date
                            example: '2026-07-07'
                          seconds:
                            type: integer
                            example: 28800
                    working_days:
                      type: number
                      description: |
                        How long the booking is, in working days the employee actually consumes: weekends, public holidays, company special holidays and days already taken by another absence are excluded, and each remaining day is measured against that employee's own scheduled day. A part-timer's 4h day therefore counts as 1, while 4h out of an 8h day counts as 0.5. Whole counts serialize without a fractional part (3, not 3.0), so decode this as a float rather than an integer.
                      example: 3
                    workshift_seconds_per_day:
                      type: integer
                      description: |
                        What one full working day is worth for this employee, in seconds: 28800 on a standard 8h shift, 14400 for somebody contracted to 4h days. Use it instead of assuming 8h. 0 when no contract or work shift resolves, which should be read as unknown.
                      example: 28800
                    is_half_day:
                      type: boolean
                      description: 'True when either end of the booking is a half day.'
                      example: false
                    starts_half_day:
                      type: boolean
                      description: |
                        True when the first day is a half day: the employee works that morning and then leaves. `start_time` carries the hour.
                      example: false
                    ends_half_day:
                      type: boolean
                      description: |
                        True when the last day is a half day: the absence covers that morning and the employee is back afterwards. `end_time` carries the hour. On a single-day half day this and `starts_half_day` are both true.
                      example: false
                    start_time:
                      type:
                        - string
                        - 'null'
                      description: |
                        Local wall-clock hour (HH:MM) the absence begins on a half-day start, null otherwise. Taken from the booking's own stored time when it has one, else the tenant's configured AM/PM split (default 12:00).
                      example: null
                    end_time:
                      type:
                        - string
                        - 'null'
                      description: |
                        Local wall-clock hour (HH:MM) the absence ends on a half-day end, null otherwise. Same source as `start_time`.
                      example: null
                    working_day_details:
                      type: array
                      description: |
                        Per-day breakdown holding working days only, ascending by date, with the half-day verdict and hours resolved per day. Hours only ever land on the two ends: a day in the middle of a range has no clock time of its own, and a single-day booking is both ends at once.
                      items:
                        type: object
                        properties:
                          date:
                            type: string
                            format: date
                            example: '2026-07-07'
                          seconds:
                            type: integer
                            description: "Seconds booked off that day, scaled to the employee's own day."
                            example: 28800
                          is_half_day:
                            type: boolean
                            description: |
                              True when this day's seconds fall short of `workshift_seconds_per_day` by more than 900 (a tolerance for lunch and rounding).
                            example: false
                          start_time:
                            type:
                              - string
                              - 'null'
                            description: 'HH:MM; non-null only on a half-day first day.'
                            example: null
                          end_time:
                            type:
                              - string
                              - 'null'
                            description: 'HH:MM; non-null only on a half-day last day.'
                            example: null
              examples:
                spanningAWeekend:
                  summary: 'A booking written before the per-day map held working days only'
                  description: |
                    Fri 2026-08-07 to Mon 2026-08-10, a half day on the Friday. `days` still carries the weekend as two 0-second entries, which is why it has four items where `working_day_details` has two.
                  value:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440030
                      employee_id: 550e8400-e29b-41d4-a716-446655440001
                      employee_name: 'Jane Smith'
                      department_id: 550e8400-e29b-41d4-a716-446655440042
                      type: legal
                      sub_type: null
                      status: approved
                      start: '2026-08-07'
                      end: '2026-08-10'
                      total_seconds: 43200
                      days:
                        -
                          date: '2026-08-07'
                          seconds: 14400
                        -
                          date: '2026-08-08'
                          seconds: 0
                        -
                          date: '2026-08-09'
                          seconds: 0
                        -
                          date: '2026-08-10'
                          seconds: 28800
                      working_days: 1.5
                      workshift_seconds_per_day: 28800
                      is_half_day: true
                      starts_half_day: true
                      ends_half_day: false
                      start_time: '12:00'
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-07'
                          seconds: 14400
                          is_half_day: true
                          start_time: '12:00'
                          end_time: null
                        -
                          date: '2026-08-10'
                          seconds: 28800
                          is_half_day: false
                          start_time: null
                          end_time: null
                wholeWeek:
                  summary: 'A whole Monday to Friday, no half day'
                  value:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440031
                      employee_id: 550e8400-e29b-41d4-a716-446655440002
                      employee_name: 'Alex Doe'
                      department_id: null
                      type: illness
                      sub_type: null
                      status: pending
                      start: '2026-08-03'
                      end: '2026-08-07'
                      total_seconds: 144000
                      days:
                        -
                          date: '2026-08-03'
                          seconds: 28800
                        -
                          date: '2026-08-04'
                          seconds: 28800
                        -
                          date: '2026-08-05'
                          seconds: 28800
                        -
                          date: '2026-08-06'
                          seconds: 28800
                        -
                          date: '2026-08-07'
                          seconds: 28800
                      working_days: 5
                      workshift_seconds_per_day: 28800
                      is_half_day: false
                      starts_half_day: false
                      ends_half_day: false
                      start_time: null
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-03'
                          seconds: 28800
                          is_half_day: false
                          start_time: null
                          end_time: null
                        -
                          date: '2026-08-07'
                          seconds: 28800
                          is_half_day: false
                          start_time: null
                          end_time: null
                partTimer:
                  summary: 'A part-timer on 4h days, two whole days off'
                  description: |
                    `workshift_seconds_per_day` is 14400, so 14400 per day is a WHOLE day and `is_half_day` is false. Reading 8h would have called these half days.
                  value:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440032
                      employee_id: 550e8400-e29b-41d4-a716-446655440005
                      employee_name: 'Sam Lee'
                      department_id: null
                      type: legal
                      sub_type: null
                      status: approved
                      start: '2026-08-03'
                      end: '2026-08-04'
                      total_seconds: 28800
                      days:
                        -
                          date: '2026-08-03'
                          seconds: 14400
                        -
                          date: '2026-08-04'
                          seconds: 14400
                      working_days: 2
                      workshift_seconds_per_day: 14400
                      is_half_day: false
                      starts_half_day: false
                      ends_half_day: false
                      start_time: null
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-03'
                          seconds: 14400
                          is_half_day: false
                          start_time: null
                          end_time: null
                        -
                          date: '2026-08-04'
                          seconds: 14400
                          is_half_day: false
                          start_time: null
                          end_time: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The caller belongs to another tenant, has no employee record, or has no active company.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/calendar/home-office':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCalendar
      summary: 'Company home office calendar'
      operationId: tempusHomeOfficeCalendar
      description: |
        Lightweight home office calendar for the caller's company: every colleague's home office bookings in the `pending`, `approved` and `pending_removal` states. Any employee in the company may read it (a team availability view); this is intentionally not scoped to the caller's own records and carries only the fields a calendar needs - full request detail lives on the `home-office-requests` endpoints. The response is a flat array, not wrapped in a `data` envelope and not paginated. Cancellation-in-progress rows appear once (the original, as `pending_removal`); the internal removal credit is omitted.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[department_id]'
          in: query
          required: false
          description: "Narrow to one or more departments (comma-separated), by the employee's active contract. Omit for the whole company."
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440042
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Only events overlapping on or after this date (`Y-m-d`).'
          schema:
            type: string
            format: date
          example: '2026-07-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Only events overlapping on or before this date (`Y-m-d`).'
          schema:
            type: string
            format: date
          example: '2026-07-31'
      responses:
        200:
          description: 'The company home office calendar. Flat array, not wrapped in data, not paginated.'
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                      example: 550e8400-e29b-41d4-a716-446655440030
                    employee_id:
                      type: string
                      format: uuid
                      example: 550e8400-e29b-41d4-a716-446655440001
                    employee_name:
                      type:
                        - string
                        - 'null'
                      example: 'Jane Smith'
                    department_id:
                      type:
                        - string
                        - 'null'
                      format: uuid
                      description: "Department of the employee's active contract; null when none."
                      example: 550e8400-e29b-41d4-a716-446655440042
                    type:
                      type: string
                      enum:
                        - home_office
                      example: home_office
                    sub_type:
                      type:
                        - string
                        - 'null'
                      example: null
                    status:
                      type: string
                      enum:
                        - pending
                        - approved
                        - pending_removal
                      example: approved
                    start:
                      type: string
                      format: date
                      example: '2026-07-07'
                    end:
                      type: string
                      format: date
                      example: '2026-07-07'
                    total_seconds:
                      type: integer
                      description: 'Total booked time across all days, in seconds.'
                      example: 28800
                    days:
                      type: array
                      description: |
                        Every entry of the booking's raw per-day map. Home office is one row per date, so this normally holds a single day. `working_day_details` below is the same breakdown with any non-working day dropped and the half-day hours resolved; both are returned, and this one is unchanged.
                      items:
                        type: object
                        properties:
                          date:
                            type: string
                            format: date
                            example: '2026-07-07'
                          seconds:
                            type: integer
                            example: 28800
                    working_days:
                      type: number
                      description: |
                        How long the booking is, in working days the employee actually consumes, each measured against that employee's own scheduled day. A part-timer's 4h day counts as 1, while 4h out of an 8h day counts as 0.5. Home office is one whole day per row, so this is normally 1. Whole counts serialize without a fractional part (1, not 1.0), so decode this as a float rather than an integer.
                      example: 1
                    workshift_seconds_per_day:
                      type: integer
                      description: |
                        What one full working day is worth for this employee, in seconds: 28800 on a standard 8h shift, 14400 for somebody contracted to 4h days. Use it instead of assuming 8h. 0 when no contract or work shift resolves, which should be read as unknown.
                      example: 28800
                    is_half_day:
                      type: boolean
                      description: |
                        True when either end of the booking is a half day. Normally false for home office, which is booked as whole days.
                      example: false
                    starts_half_day:
                      type: boolean
                      description: 'True when the first day is a half day: worked that morning, then away.'
                      example: false
                    ends_half_day:
                      type: boolean
                      description: |
                        True when the last day is a half day. On a single-day booking this and `starts_half_day` are both true.
                      example: false
                    start_time:
                      type:
                        - string
                        - 'null'
                      description: |
                        Local wall-clock hour (HH:MM) the day begins on a half-day start, null otherwise. Taken from the booking's own stored time when it has one, else the tenant's configured AM/PM split (default 12:00).
                      example: null
                    end_time:
                      type:
                        - string
                        - 'null'
                      description: |
                        Local wall-clock hour (HH:MM) the day ends on a half-day end, null otherwise. Same source as `start_time`.
                      example: null
                    working_day_details:
                      type: array
                      description: |
                        Per-day breakdown holding working days only, ascending by date, with the half-day verdict and hours resolved per day.
                      items:
                        type: object
                        properties:
                          date:
                            type: string
                            format: date
                            example: '2026-07-07'
                          seconds:
                            type: integer
                            description: "Seconds booked off that day, scaled to the employee's own day."
                            example: 28800
                          is_half_day:
                            type: boolean
                            description: |
                              True when this day's seconds fall short of `workshift_seconds_per_day` by more than 900 (a tolerance for lunch and rounding).
                            example: false
                          start_time:
                            type:
                              - string
                              - 'null'
                            description: 'HH:MM; non-null only on a half-day first day.'
                            example: null
                          end_time:
                            type:
                              - string
                              - 'null'
                            description: 'HH:MM; non-null only on a half-day last day.'
                            example: null
              examples:
                twoSeparateDays:
                  summary: 'Two home office days, one row each'
                  description: |
                    Home office is stored one row per date, so each entry is a single whole day and `working_days` is 1.
                  value:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440050
                      employee_id: 550e8400-e29b-41d4-a716-446655440001
                      employee_name: 'Jane Smith'
                      department_id: 550e8400-e29b-41d4-a716-446655440042
                      type: home_office
                      sub_type: null
                      status: approved
                      start: '2026-08-04'
                      end: '2026-08-04'
                      total_seconds: 28800
                      days:
                        -
                          date: '2026-08-04'
                          seconds: 28800
                      working_days: 1
                      workshift_seconds_per_day: 28800
                      is_half_day: false
                      starts_half_day: false
                      ends_half_day: false
                      start_time: null
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-04'
                          seconds: 28800
                          is_half_day: false
                          start_time: null
                          end_time: null
                    -
                      id: 550e8400-e29b-41d4-a716-446655440051
                      employee_id: 550e8400-e29b-41d4-a716-446655440001
                      employee_name: 'Jane Smith'
                      department_id: 550e8400-e29b-41d4-a716-446655440042
                      type: home_office
                      sub_type: null
                      status: pending
                      start: '2026-08-06'
                      end: '2026-08-06'
                      total_seconds: 28800
                      days:
                        -
                          date: '2026-08-06'
                          seconds: 28800
                      working_days: 1
                      workshift_seconds_per_day: 28800
                      is_half_day: false
                      starts_half_day: false
                      ends_half_day: false
                      start_time: null
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-06'
                          seconds: 28800
                          is_half_day: false
                          start_time: null
                          end_time: null
                partTimer:
                  summary: 'A part-timer on 4h days'
                  description: |
                    `workshift_seconds_per_day` is 14400, so 14400 is a WHOLE day here and `is_half_day` stays false.
                  value:
                    -
                      id: 550e8400-e29b-41d4-a716-446655440052
                      employee_id: 550e8400-e29b-41d4-a716-446655440005
                      employee_name: 'Sam Lee'
                      department_id: null
                      type: home_office
                      sub_type: null
                      status: approved
                      start: '2026-08-05'
                      end: '2026-08-05'
                      total_seconds: 14400
                      days:
                        -
                          date: '2026-08-05'
                          seconds: 14400
                      working_days: 1
                      workshift_seconds_per_day: 14400
                      is_half_day: false
                      starts_half_day: false
                      ends_half_day: false
                      start_time: null
                      end_time: null
                      working_day_details:
                        -
                          date: '2026-08-05'
                          seconds: 14400
                          is_half_day: false
                          start_time: null
                          end_time: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The caller belongs to another tenant, has no employee record, or has no active company.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/corrections':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCorrections
      summary: 'List timepoint corrections for the tenant (user)'
      operationId: tempusListCorrections
      description: |
        Returns a paginated list of Tempus time point corrections for the given
        Pbx (tenant). Results can be filtered by correction status and by the
        groups the requesting employee belongs to, sorted by creation time, and
        expanded with optional related data through the `include` parameter.

        Each item is serialized by the `CorrectionListResource`. The response uses
        the standard Laravel pagination envelope: a `data` array of corrections plus
        `links` and `meta` objects.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[status]'
          in: query
          required: false
          description: |
            Restrict results to corrections in the given lifecycle states. Accepts a
            repeated array parameter or a single comma-separated string.
          schema:
            type: array
            items:
              type: string
              enum:
                - pending
                - accepted
                - rejected
                - canceled
                - rejected_closed
          example:
            - pending
        -
          name: 'filter[group_id]'
          in: query
          required: false
          description: |
            Restrict results to corrections whose requesting employee belongs to one
            of the given group identifiers. Accepts a repeated array parameter or a
            single comma-separated string of UUIDs.
          schema:
            type: array
            items:
              type: string
              format: uuid
          example:
            - 550e8400-e29b-41d4-a716-446655440010
        -
          name: sort
          in: query
          required: false
          description: |
            Sort order by creation time. `create_time` is ascending, `-create_time`
            is descending. Defaults to `-create_time`.
          schema:
            type: string
            enum:
              - create_time
              - '-create_time'
          example: '-create_time'
        -
          name: include
          in: query
          required: false
          description: |
            Comma-separated list of optional expansions to include on each
            correction. Allowed values are `requesterExt`, `newStatus`, and
            `oldStatus`. Unknown values are ignored.
          schema:
            type: string
          example: 'requesterExt,newStatus'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page (1-100). Defaults to 15.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 15
      responses:
        200:
          description: 'Paginated list of corrections.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusCorrectionList'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is not authorized for this tenant (the request
            fails the FormRequest authorization check).
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/calendar':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCalendar
      summary: 'Employee calendar for the logged-in user'
      operationId: tempusGetUserCalendar
      description: |
        Returns the data behind the Tempus "Employee Calendar" page for the
        **logged-in user**, for a single year: the summary block, the per-company
        rights breakdown (`details`), contract periods, and a fully-classified
        day-by-day `year_calendar`. Plain data only: no colours, icons or theme;
        the client owns presentation.

        The employee is resolved from the Sanctum token; there is no employee
        parameter and a caller can only ever read their own calendar. The only
        input is the `year` (bounded to the employee's contract history through
        next year).

        Per-day `type` merge priority (highest first): `no_contract` >
        `special_holiday` > transaction (non-home-office) > `public_holiday` >
        `weekend` > `work`. Home office is an orthogonal flag, never the winning
        type.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: year
          in: query
          required: false
          description: |
            Calendar year to return. Must fall within the employee's
            `[minYear, maxYear]` bounds (earliest contract year … current year + 1).
            Defaults to the current year. Out-of-range values return 422.
          schema:
            type: integer
          example: 2026
      responses:
        200:
          description: "The employee's calendar for the requested year."
          content:
            application/json:
              schema:
                type: object
                description: |
                  Employee Calendar payload for one year, as plain presentation-free data:
                  summary block, per-company rights breakdown (details), and a day-by-day
                  year calendar covering every date. Scoped to the logged-in user (the employee
                  is resolved from the token), so it carries no employee identity, no colours,
                  and no theme.
                required:
                  - year
                  - year_bounds
                  - summary
                  - details
                  - contract_periods
                  - daily_expected_seconds
                  - year_calendar
                properties:
                  year:
                    type: integer
                    example: 2026
                  year_bounds:
                    type: object
                    description: 'Selectable year range for the year filter (earliest contract year through next year).'
                    properties:
                      min:
                        type: integer
                      max:
                        type: integer
                    example:
                      min: 2023
                      max: 2027
                  summary:
                    type: object
                    description: 'Aggregate rights/taken/remaining for the year.'
                    properties:
                      totals:
                        type: object
                        description: 'Aggregate seconds for the year.'
                        properties:
                          rights:
                            type: integer
                          taken:
                            type: integer
                          remaining:
                            type: integer
                          compensatory:
                            type: integer
                          available:
                            type: integer
                      cards:
                        type: array
                        description: 'The headline figures shown as summary cards.'
                        items:
                          type: object
                          properties:
                            key:
                              type: string
                              enum:
                                - rights
                                - taken
                                - remaining_rights
                                - compensatory_balance
                                - possible
                            title:
                              type:
                                - string
                                - 'null'
                            value:
                              type:
                                - string
                                - 'null'
                              description: 'Human display (days or hours), e.g. "26 days".'
                            raw_seconds:
                              type: integer
                            percentage:
                              type:
                                - number
                                - 'null'
                            warning:
                              type: boolean
                              description: 'True when the value fell back to an 8h/day assumption (no workshift).'
                            comment:
                              type:
                                - string
                                - 'null'
                      handle_compensatory_balance:
                        type: boolean
                      workshift_missing:
                        type: boolean
                        description: 'True when no contract/workshift is set, so days-vs-hours fell back to 8h.'
                  details:
                    type: object
                    description: 'Per-company rights breakdown for the whole year.'
                    properties:
                      total_seconds:
                        type: integer
                      total_display:
                        type: string
                      companies:
                        type: array
                        items:
                          type: object
                          properties:
                            company_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            company:
                              type:
                                - string
                                - 'null'
                            period_label:
                              type:
                                - string
                                - 'null'
                            periods:
                              type: array
                              items:
                                type: object
                                properties:
                                  start:
                                    type: string
                                    format: date
                                  end:
                                    type: string
                                    format: date
                            show_period:
                              type: boolean
                            switched_on:
                              type:
                                - string
                                - 'null'
                            subtotal_seconds:
                              type: integer
                            subtotal_display:
                              type:
                                - string
                                - 'null'
                            rows:
                              type: array
                              items:
                                type: object
                                properties:
                                  type:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Human label of the holiday pool.'
                                  type_key:
                                    type:
                                      - string
                                      - 'null'
                                    description: 'Machine key, e.g. legal, age, public_holiday.'
                                  description:
                                    type:
                                      - string
                                      - 'null'
                                  rights_seconds:
                                    type: integer
                                  rights_display:
                                    type:
                                      - string
                                      - 'null'
                  contract_periods:
                    type: array
                    description: "The employee's contract periods clamped to the year."
                    items:
                      type: object
                      properties:
                        start:
                          type: string
                          format: date
                        end:
                          type: string
                          format: date
                  daily_expected_seconds:
                    type: integer
                    description: 'Expected working seconds per day for the year (weekly time ÷ 5).'
                    example: 28800
                  year_calendar:
                    type: object
                    description: |
                      Every date of the year (YYYY-MM-DD keys) mapped to its classified day.
                    additionalProperties:
                      type: object
                      description: 'A single classified calendar day.'
                      properties:
                        date:
                          type: string
                          format: date
                        weekday:
                          type: integer
                          description: 'ISO weekday, 1 (Mon) … 7 (Sun).'
                        is_weekend:
                          type: boolean
                        in_contract:
                          type: boolean
                        type:
                          type: string
                          description: |
                            Winning classification, decided with priority (highest first):
                            no_contract > special_holiday > transaction (non-home-office) >
                            public_holiday > weekend > work.
                          enum:
                            - work
                            - weekend
                            - no_contract
                            - public_holiday
                            - special_holiday
                            - legal
                            - absence
                            - illness
                            - special
                        status:
                          type:
                            - string
                            - 'null'
                          description: 'Set for transaction days only.'
                          enum:
                            - approved
                            - pending
                            - pending_removal
                            - rejected
                            - cancelled
                            - removed
                            - null
                        sub_type:
                          type:
                            - string
                            - 'null'
                        sub_type_label:
                          type:
                            - string
                            - 'null'
                          description: 'Human label, e.g. "Sick child".'
                        note:
                          type:
                            - string
                            - 'null'
                        start_time:
                          type:
                            - string
                            - 'null'
                        end_time:
                          type:
                            - string
                            - 'null'
                        is_first_day:
                          type:
                            - boolean
                            - 'null'
                        is_last_day:
                          type:
                            - boolean
                            - 'null'
                        is_single_day:
                          type:
                            - boolean
                            - 'null'
                        seconds:
                          type:
                            - integer
                            - 'null'
                          description: 'Seconds booked this day (transaction days).'
                        expected_seconds:
                          type: integer
                        home_office:
                          type:
                            - object
                            - 'null'
                          description: 'Home office flag (present regardless of the base type).'
                          properties:
                            present:
                              type: boolean
                            status:
                              type: string
                        public_holiday:
                          type:
                            - object
                            - 'null'
                          properties:
                            name:
                              type:
                                - string
                                - 'null'
                        special_holiday:
                          type:
                            - object
                            - 'null'
                          properties:
                            title:
                              type:
                                - string
                                - 'null'
                        transactions:
                          type: array
                          description: 'All bookings on this day (for multi-event days).'
                          items:
                            type: object
                            properties:
                              id:
                                type:
                                  - string
                                  - 'null'
                                format: uuid
                              type:
                                type:
                                  - string
                                  - 'null'
                              sub_type:
                                type:
                                  - string
                                  - 'null'
                              status:
                                type:
                                  - string
                                  - 'null'
                              seconds:
                                type: integer
                              start_time:
                                type:
                                  - string
                                  - 'null'
                              end_time:
                                type:
                                  - string
                                  - 'null'
                              note:
                                type:
                                  - string
                                  - 'null'
        401:
          description: Unauthenticated.
        403:
          description: 'The authenticated user has no employee record in this Pbx.'
        422:
          description: "The requested year is outside the employee's allowed range."
  '/{pbx_id}/validators':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'List all validators in the tenant'
      operationId: tempusListValidators
      description: |
        Every validator in the tenant (an employee named on any validator rule),
        with the per-module permissions they hold and the lightweight list of
        employees they validate (the union across their rules' company / department /
        employees scope). Readable by any authenticated user in the tenant.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'The validators in the tenant.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - validator
                        - permissions
                        - employees
                      properties:
                        validator:
                          type: object
                          properties:
                            employee_id:
                              type: string
                              format: uuid
                            user_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            name:
                              type: string
                        permissions:
                          type: object
                          description: 'Which validator modules the caller may act on for this employee.'
                          properties:
                            holiday_requests:
                              type: boolean
                            home_office_requests:
                              type: boolean
                            time_point_corrections_requests:
                              type: boolean
                            schedules_management:
                              type: boolean
                        employees:
                          type: array
                          description: 'Lightweight list of the employees this validator may consult.'
                          items:
                            type: object
                            properties:
                              employee_id:
                                type: string
                                format: uuid
                              name:
                                type: string
              example:
                data:
                  -
                    validator:
                      employee_id: 550e8400-e29b-41d4-a716-446655440000
                      user_id: 550e8400-e29b-41d4-a716-446655440001
                      name: 'Jane Smith'
                    permissions:
                      holiday_requests: true
                      home_office_requests: true
                      time_point_corrections_requests: false
                      schedules_management: false
                    employees:
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440010
                        name: 'John Doe'
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440011
                        name: 'Mary Jones'
        401:
          description: Unauthenticated.
        403:
          description: 'The caller does not belong to this tenant.'
  '/{pbx_id}/validator/employees':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'Employees the logged-in validator can validate'
      operationId: tempusListValidatorEmployees
      description: |
        Returns the employees the logged-in user (a validator) is allowed to
        validate (the union across all validator modules), each with identity, the
        active contract, and a per-module capability map. Access is rule-based
        (see the "Validators & Managers" rules). Matricule is never returned.

        Optional filters narrow the list by the employee's active-contract company or
        department, or to a single employee. The dropdown values (the companies /
        departments / employees in scope) come from the caller's user-profile
        `validator` block.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[company_id]'
          in: query
          required: false
          description: 'Keep only employees whose active contract is in this company.'
          schema:
            type: string
            format: uuid
        -
          name: 'filter[department_id]'
          in: query
          required: false
          description: 'Keep only employees whose active contract is in this department.'
          schema:
            type: string
            format: uuid
        -
          name: 'filter[employee_id]'
          in: query
          required: false
          description: 'Keep only this employee (when in scope).'
          schema:
            type: string
            format: uuid
      responses:
        200:
          description: "The employees in the validator's scope."
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        employee_id:
                          type: string
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440010
                        user_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440011
                        first_name:
                          type:
                            - string
                            - 'null'
                          example: John
                        last_name:
                          type:
                            - string
                            - 'null'
                          example: Doe
                        email:
                          type:
                            - string
                            - 'null'
                          example: john.doe@example.com
                        extension_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                          example: 550e8400-e29b-41d4-a716-446655440020
                        is_active:
                          type: boolean
                          example: true
                        contract:
                          type:
                            - object
                            - 'null'
                          description: "The employee's active contract, or null when none is active."
                          properties:
                            start_date:
                              type:
                                - string
                                - 'null'
                              format: date
                            end_date:
                              type:
                                - string
                                - 'null'
                              format: date
                            weekly_expected_working_time_seconds:
                              type: integer
                            weekly_expected_working_time:
                              type: string
                              description: 'HH:MM.'
                            participation:
                              type:
                                - number
                                - 'null'
                              description: 'FTE fraction, e.g. 100 or 80.'
                            job_title:
                              type:
                                - string
                                - 'null'
                            contract_type:
                              type:
                                - string
                                - 'null'
                            company_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            company:
                              type:
                                - string
                                - 'null'
                            department_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            department:
                              type:
                                - string
                                - 'null'
                            compensatory_balance_seconds:
                              type: integer
                            ho_balance_seconds:
                              type: integer
                        modules:
                          type: object
                          description: 'Which validator modules the caller may act on for this employee.'
                          properties:
                            holiday_requests:
                              type: boolean
                            home_office_requests:
                              type: boolean
                            time_point_corrections_requests:
                              type: boolean
                            schedules_management:
                              type: boolean
        401:
          description: Unauthenticated.
        403:
          description: 'The caller has no employee record in this tenant.'
        422:
          description: 'A filter value is not a valid UUID.'
  '/{pbx_id}/validator/{employee_id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'Validator-scoped employee profile'
      operationId: tempusGetValidatorEmployeeProfile
      description: |
        Full profile of one employee as a validator sees it: identity, active
        contract, active workshift, work hours (worked vs required, overtime on
        business vs off days), legal-holiday balance, and leave / home-office /
        correction history for the range. Returns `403` unless the target employee
        is within the caller's validator scope. Matricule is never returned.
        Transaction/correction `status` values are the raw ledger values.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Y-m-d. Defaults to the start of the current month. Range max 100 days.'
          schema:
            type: string
            format: date
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Y-m-d. Defaults to today.'
          schema:
            type: string
            format: date
      responses:
        200:
          description: "The employee's validator-facing profile."
          content:
            application/json:
              schema:
                type: object
                properties:
                  employee:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      user_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      first_name:
                        type:
                          - string
                          - 'null'
                      last_name:
                        type:
                          - string
                          - 'null'
                      email:
                        type:
                          - string
                          - 'null'
                      is_active:
                        type: boolean
                  contract:
                    type:
                      - object
                      - 'null'
                    description: "The employee's active contract, or null when none is active."
                    properties:
                      start_date:
                        type:
                          - string
                          - 'null'
                        format: date
                      end_date:
                        type:
                          - string
                          - 'null'
                        format: date
                      weekly_expected_working_time_seconds:
                        type: integer
                      weekly_expected_working_time:
                        type: string
                        description: 'HH:MM.'
                      participation:
                        type:
                          - number
                          - 'null'
                        description: 'FTE fraction, e.g. 100 or 80.'
                      job_title:
                        type:
                          - string
                          - 'null'
                      contract_type:
                        type:
                          - string
                          - 'null'
                      company_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      company:
                        type:
                          - string
                          - 'null'
                      department_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      department:
                        type:
                          - string
                          - 'null'
                      compensatory_balance_seconds:
                        type: integer
                      ho_balance_seconds:
                        type: integer
                  workshift:
                    type:
                      - object
                      - 'null'
                    properties:
                      id:
                        type: string
                        format: uuid
                      title:
                        type:
                          - string
                          - 'null'
                      detail:
                        type:
                          - string
                          - 'null'
                      weekly_seconds:
                        type: integer
                      weekly:
                        type: string
                        description: 'HH:MM.'
                      working_hours:
                        type: object
                        description: 'Seconds per weekday (mon..sun).'
                        additionalProperties:
                          type: integer
                      assignment:
                        type: object
                        properties:
                          start_date:
                            type:
                              - string
                              - 'null'
                            format: date
                          end_date:
                            type:
                              - string
                              - 'null'
                            format: date
                          is_default:
                            type: boolean
                  range:
                    type: object
                    properties:
                      from:
                        type: string
                        format: date
                      to:
                        type: string
                        format: date
                  work_hours:
                    type: object
                    description: |
                      Keyed by week-start date (Monday) plus a `summary` key. Each
                      bucket: totalWorkedTime, requiredWorkedTime,
                      businessDaysWorkedTime, nonWorkingDaysWorkedTime (HH:MM:SS),
                      each mirrored by a signed `<field>Seconds` integer, plus hasOvertime
                      and minWorkTimeReached. The overtime figures are balances and
                      go negative for a week under the required time, so the weekly
                      buckets sum to `summary`. Days after today are excluded.
                    additionalProperties:
                      type: object
                  holiday_balance:
                    type: object
                    properties:
                      year:
                        type: integer
                      rights_seconds:
                        type: integer
                      taken_seconds:
                        type: integer
                      remaining_seconds:
                        type: integer
                      compensatory_seconds:
                        type: integer
                      available_seconds:
                        type: integer
                  leave:
                    type: array
                    items:
                      type: object
                      description: 'A leave or home-office request overlapping the range.'
                      properties:
                        id:
                          type: string
                          format: uuid
                        type:
                          type:
                            - string
                            - 'null'
                          description: 'legal | absence | illness | special | home_office.'
                        sub_type:
                          type:
                            - string
                            - 'null'
                        status:
                          type:
                            - string
                            - 'null'
                          description: 'Raw ledger status.'
                          enum:
                            - pending
                            - approved
                            - rejected
                            - cancelled
                            - pending_removal
                            - removed
                            - null
                        start:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        end:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        requested_seconds:
                          type: integer
                        comment:
                          type:
                            - string
                            - 'null'
                        created:
                          type:
                            - string
                            - 'null'
                          format: date-time
                  home_office:
                    type: array
                    items:
                      type: object
                      description: 'A leave or home-office request overlapping the range.'
                      properties:
                        id:
                          type: string
                          format: uuid
                        type:
                          type:
                            - string
                            - 'null'
                          description: 'legal | absence | illness | special | home_office.'
                        sub_type:
                          type:
                            - string
                            - 'null'
                        status:
                          type:
                            - string
                            - 'null'
                          description: 'Raw ledger status.'
                          enum:
                            - pending
                            - approved
                            - rejected
                            - cancelled
                            - pending_removal
                            - removed
                            - null
                        start:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        end:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        requested_seconds:
                          type: integer
                        comment:
                          type:
                            - string
                            - 'null'
                        created:
                          type:
                            - string
                            - 'null'
                          format: date-time
                  corrections:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        status:
                          type:
                            - string
                            - 'null'
                        timepoint_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                        old_status_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                        new_status_id:
                          type:
                            - string
                            - 'null'
                          format: uuid
                        old_time:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        new_time:
                          type:
                            - string
                            - 'null'
                          format: date-time
                        correction_comment:
                          type:
                            - string
                            - 'null'
                        new_comment:
                          type:
                            - string
                            - 'null'
                        created:
                          type:
                            - string
                            - 'null'
                          format: date-time
                  modules:
                    type: object
                    description: 'Which validator modules the caller may act on for this employee.'
                    properties:
                      holiday_requests:
                        type: boolean
                      home_office_requests:
                        type: boolean
                      time_point_corrections_requests:
                        type: boolean
                      schedules_management:
                        type: boolean
        401:
          description: Unauthenticated.
        403:
          description: "Caller has no employee record, or the employee is not in the caller's scope."
        422:
          description: 'Bad date format or range exceeds 100 days.'
  '/{pbx_id}/user/{employee_id}/corrections':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCorrections
      summary: 'List timepoint corrections for an employee (user)'
      operationId: tempusListUserCorrections
      description: |
        Returns a paginated list of Tempus time point corrections belonging to a
        single employee within the given Pbx (tenant), optionally filtered by
        correction status and ordered by creation time (newest first).

        Each item is serialized by the `CorrectionResource`. The response uses the
        standard Laravel pagination envelope: a `data` array of corrections plus
        `links` and `meta` objects.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: employee_id
          in: path
          required: true
          description: 'Identifier of the Tempus employee whose corrections are listed.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
        -
          name: 'filter[status]'
          in: query
          required: false
          description: |
            Restrict results to corrections in the given lifecycle states. Accepts a
            repeated array parameter or a single comma-separated string.
          schema:
            type: array
            items:
              type: string
              enum:
                - pending
                - accepted
                - rejected
                - canceled
                - rejected_closed
          example:
            - pending
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page (1-100). Defaults to 15.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 15
      responses:
        200:
          description: "Paginated list of the employee's corrections."
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusCorrection'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is not authorized for this employee or tenant
            (the request fails the FormRequest authorization check).
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusCorrections
      summary: 'Create a timepoint correction for an employee, edit alias (user)'
      operationId: tempusCreateUserCorrection
      description: |
        Back-compat alias of `POST .../corrections/edit`. Prefer the explicit
        intent endpoints: `/corrections/add` (add a missing timepoint),
        `/corrections/edit` (amend an existing one), `/corrections/delete` (remove
        one).

        Creates a pending Tempus time point correction for the authenticated
        employee. A correction always amends an **existing** time point, so
        `timepoint_id` is **required** and must reference one of the employee's own
        time points in this tenant. On acceptance the referenced time point is
        updated in place (no duplicate). A `null` `new_time` requests removal of
        that time point.

        Any earlier pending correction for the same `timepoint_id` is automatically
        canceled before the new one is created. Pending validator approvals are
        generated after the correction is persisted.

        The created correction is returned as a single object serialized by the
        `StoreUserCorrectionResource` (not wrapped in a `data` envelope). Server-set
        fields such as `pbx_id`, `employee_id`, the resolved old values, and
        `status` are not accepted in the request body.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: employee_id
          in: path
          required: true
          description: "Identifier of the Tempus employee the correction is created for (must match the authenticated user's own employee)."
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: |
                Correction payload. Amends the existing time point referenced by
                `timepoint_id` (required).
              required:
                - timepoint_id
              properties:
                timepoint_id:
                  type: string
                  format: uuid
                  description: |
                    Identifier of the existing time point to correct. **Required.**
                    Must reference a time point in this tenant that belongs to the
                    authenticated employee's own user.
                  example: 550e8400-e29b-41d4-a716-446655440002
                new_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Identifier of the Tempus status to apply. Must reference a status
                    in the same tenant. Optional.
                  example: 550e8400-e29b-41d4-a716-446655440004
                new_sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Identifier of the Tempus sub-status to apply. Must reference a
                    sub-status in the same tenant. Optional.
                  example: 550e8400-e29b-41d4-a716-446655440005
                new_location_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Request that the time point be moved to a different location.

                    Verified when the request is raised, by the same rule the live
                    change-status endpoint applies: the location must belong to this
                    tenant and be enabled for presence status. Anything else is a
                    422, so a correction cannot reach a location a normal punch would
                    have been refused.

                    Unlike `new_status_id` this does NOT default to the time point's
                    current value. Omitting it (or sending null) means the correction
                    does not touch the location, and acceptance leaves it exactly as
                    it is. There is deliberately no way to clear a location through a
                    correction: on the stored row, null cannot be told apart from
                    "no location change was requested".
                  example: 550e8400-e29b-41d4-a716-446655440010
                new_time:
                  type:
                    - string
                    - 'null'
                  description: |
                    Requested timestamp for the corrected entry, in `Y-m-d H:i:s`
                    format. Optional. `null` requests removal of the time point.
                  example: '2024-03-01 08:30:00'
                correction_comment:
                  type:
                    - string
                    - 'null'
                  description: 'Free-form justification for the correction.'
                  example: 'Forgot to clock in after lunch break.'
                new_comment:
                  type:
                    - string
                    - 'null'
                  description: 'Comment to apply to the corrected or newly created time point.'
                  example: 'Corrected start time per manager approval.'
            example:
              timepoint_id: 550e8400-e29b-41d4-a716-446655440002
              new_status_id: 550e8400-e29b-41d4-a716-446655440004
              new_location_id: 550e8400-e29b-41d4-a716-446655440010
              new_time: '2024-03-01 08:30:00'
              correction_comment: 'Forgot to clock in after lunch break.'
      responses:
        201:
          description: 'The created correction.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is not authorized for this employee or tenant, or
            has no linked employee record (the request fails authorization).
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/corrections/add':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusCorrections
      summary: 'Add-a-missing-timepoint correction (user)'
      operationId: tempusAddUserCorrection
      description: |
        Creates a pending correction that requests a BRAND-NEW timepoint: there is
        no existing timepoint, so `timepoint_id` must be omitted. On validator
        acceptance a timepoint is created (never a duplicate). Self-scoped: the
        authenticated user must be the `{employee_id}`. Any prior pending "add"
        correction by this employee is auto-canceled first.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - new_status_id
                - new_time
              properties:
                new_status_id:
                  type: string
                  format: uuid
                  description: 'Status for the new timepoint. Must exist in this tenant. Required.'
                new_time:
                  type: string
                  description: 'Timestamp for the new timepoint, `Y-m-d H:i:s`. Required.'
                  example: '2026-03-02 08:30:00'
                new_sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                new_location_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Location the new timepoint should be recorded at. Optional; omit
                    or send null for no location.

                    Verified when the request is raised, by the same rule the live
                    change-status endpoint applies: the location must belong to this
                    tenant and be enabled for presence status. Anything else is a
                    422, so a correction cannot reach a location a normal punch would
                    have been refused.
                  example: 550e8400-e29b-41d4-a716-446655440010
                correction_comment:
                  type:
                    - string
                    - 'null'
                new_comment:
                  type:
                    - string
                    - 'null'
            example:
              new_status_id: 550e8400-e29b-41d4-a716-446655440004
              new_time: '2026-03-02 08:30:00'
              new_location_id: 550e8400-e29b-41d4-a716-446655440010
              correction_comment: 'Forgot to clock in.'
      responses:
        201:
          description: 'The created (pending) correction.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Not authorized for this employee/tenant, or no linked employee record.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/corrections/edit':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusCorrections
      summary: 'Edit-an-existing-timepoint correction (user)'
      operationId: tempusEditUserCorrection
      description: |
        Creates a pending correction that amends an EXISTING timepoint.
        `timepoint_id` is required and must be one of the requesting employee's own
        timepoints. On validator acceptance the timepoint is updated in place, with no
        duplicate. `new_time` is optional; if omitted it defaults to the timepoint's
        current time (so a status-only edit is never read as a removal). Base
        `POST .../corrections` (no suffix) is a back-compat alias of this endpoint.
        Any prior pending correction for the same timepoint is auto-canceled first.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - timepoint_id
              properties:
                timepoint_id:
                  type: string
                  format: uuid
                  description: "The existing timepoint to edit. Must belong to the authenticated employee's own user. Required."
                new_time:
                  type:
                    - string
                    - 'null'
                  description: "New timestamp, `Y-m-d H:i:s`. Optional; defaults to the timepoint's current time."
                  example: '2026-03-02 08:00:00'
                new_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                new_sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                new_location_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Request that the timepoint be moved to a different location.

                    Verified when the request is raised, by the same rule the live
                    change-status endpoint applies: the location must belong to this
                    tenant and be enabled for presence status. Anything else is a
                    422, so a correction cannot reach a location a normal punch would
                    have been refused.

                    Unlike `new_status_id` this does NOT default to the timepoint's
                    current value. Omitting it (or sending null) means the correction
                    does not touch the location, and acceptance leaves it exactly as
                    it is. There is deliberately no way to clear a location through a
                    correction: on the stored row, null cannot be told apart from
                    "no location change was requested".
                  example: 550e8400-e29b-41d4-a716-446655440010
                correction_comment:
                  type:
                    - string
                    - 'null'
                new_comment:
                  type:
                    - string
                    - 'null'
            example:
              timepoint_id: 550e8400-e29b-41d4-a716-446655440002
              new_status_id: 550e8400-e29b-41d4-a716-446655440004
              new_location_id: 550e8400-e29b-41d4-a716-446655440010
              new_time: '2026-03-02 08:00:00'
      responses:
        201:
          description: 'The created (pending) correction.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Not authorized for this employee/tenant, or no linked employee record.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/corrections/delete':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusCorrections
      summary: 'Delete-a-timepoint correction (user)'
      operationId: tempusDeleteUserCorrection
      description: |
        Requests removal of an EXISTING timepoint. `timepoint_id` is required and
        must be one of the requesting employee's own timepoints. Two outcomes:

        - If there is **no** pending correction for that timepoint, a pending delete
          request is created (`201`); on validator acceptance the timepoint is
          removed.
        - If a correction for that timepoint is **already pending**, that pending
          request is canceled directly (`200`, no new request and no approval);
          i.e. delete retracts the outstanding correction.

        Self-scoped: the authenticated user must be the `{employee_id}`.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - timepoint_id
              properties:
                timepoint_id:
                  type: string
                  format: uuid
                  description: "The existing timepoint to remove. Must belong to the authenticated employee's own user. Required."
                correction_comment:
                  type:
                    - string
                    - 'null'
                new_comment:
                  type:
                    - string
                    - 'null'
            example:
              timepoint_id: 550e8400-e29b-41d4-a716-446655440002
              correction_comment: 'Wrong entry.'
      responses:
        201:
          description: 'A pending delete correction was created.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        200:
          description: 'An already-pending correction for the timepoint was canceled instead.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Not authorized for this employee/tenant, or no linked employee record.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/corrections/{correction_id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCorrections
      summary: 'Get a timepoint correction for an employee (user)'
      operationId: tempusGetUserCorrection
      description: |
        Returns a single Tempus time point correction belonging to the given
        employee within the tenant. The authenticated user may only read their own
        employee's corrections.

        The correction is returned as a single object serialized by the
        `CorrectionResource` (not wrapped in a `data` envelope), with the related
        time point, statuses, and sub-statuses eager loaded.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: employee_id
          in: path
          required: true
          description: "Identifier of the Tempus employee (must match the authenticated user's own employee)."
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
        -
          name: correction_id
          in: path
          required: true
          description: 'Identifier of the correction to retrieve.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        200:
          description: 'The requested correction.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no linked employee record, is requesting an
            employee other than their own, or does not belong to the tenant.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - TempusCorrections
      summary: 'Cancel a timepoint correction for an employee (user)'
      operationId: tempusUpdateUserCorrection
      description: |
        Cancels an existing Tempus time point correction for the authenticated
        employee. The only accepted `status` value is `canceled`.

        Behaviour depends on the correction's current state. A `pending` correction
        is marked `canceled` and its pending approvals are removed. An `accepted`
        correction cannot be undone directly; instead a new pending reversal
        correction (old and new values swapped) is created and returned for
        validation. Any other current state results in an error.

        The resulting correction is returned as a single object serialized by the
        `UpdateUserCorrectionResource` (not wrapped in a `data` envelope).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: employee_id
          in: path
          required: true
          description: "Identifier of the Tempus employee (must match the authenticated user's own employee)."
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
        -
          name: correction_id
          in: path
          required: true
          description: 'Identifier of the correction to cancel.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    - canceled
                  description: 'Target status. Only `canceled` is accepted.'
                  example: canceled
            example:
              status: canceled
      responses:
        200:
          description: |
            The canceled correction, or the newly created pending reversal
            correction when the original had been accepted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusCorrection'
        400:
          description: |
            The correction is neither pending nor accepted and therefore cannot be
            canceled.
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is not authorized for this employee or tenant
            (the request fails the FormRequest authorization check).
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/corrections/{correction_id}/validations':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusCorrections
      summary: 'List validation decisions for a time-point correction (user)'
      operationId: tempusListCorrectionValidations
      description: |
        Returns the paginated list of validation (approval) decisions attached to a
        single Tempus time-point correction request. Each item is a
        `TempusCorrectionApproval` recording one validator's decision. The validator
        summary is eager-loaded on every item. Results are wrapped in the standard
        Laravel pagination envelope (`data`, `links`, `meta`).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: correction_id
          in: path
          required: true
          description: 'Identifier of the Tempus time-point correction request.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: page
          in: query
          required: false
          description: 'Page number of the result set.'
          schema:
            type: integer
            minimum: 1
            example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of records per page (maximum 100).'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            example: 15
      responses:
        200:
          description: 'Paginated list of validation decisions for the correction.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusCorrectionApproval'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user does not belong to the requested tenant.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusCorrections
      summary: 'Submit a validation decision for a time-point correction (user)'
      operationId: tempusCreateCorrectionValidation
      description: |
        Records the authenticated validator's decision (accepted or rejected) for a
        Tempus time-point correction request, then applies the decision to the
        correction. If the validator already has a pending decision on this
        correction it is updated in place; a decision that has already been finalised
        cannot be resubmitted. The authenticated user must have a linked Tempus
        employee record. A requester notification email is dispatched after the
        decision is committed.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'Identifier of the Pbx (tenant).'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: correction_id
          in: path
          required: true
          description: 'Identifier of the Tempus time-point correction request.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440002
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    - accepted
                    - rejected
                  description: 'The decision being recorded for this correction.'
                  example: accepted
                comment:
                  type:
                    - string
                    - 'null'
                  description: |
                    Free-form note explaining the decision. When provided and `note`
                    is absent, it is used as the stored note.
                  maxLength: 65535
                  example: 'Approved after confirming the corrected clock-in time.'
                note:
                  type:
                    - string
                    - 'null'
                  description: 'Free-form note explaining the decision.'
                  maxLength: 65535
                  example: 'Approved after confirming the corrected clock-in time.'
                new_time:
                  type:
                    - string
                    - 'null'
                  format: date-time
                  description: 'Optional corrected time-point value to apply.'
                  example: '2024-03-01T08:00:00+00:00'
                new_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Optional identifier of the time-point status to apply.'
                  example: 550e8400-e29b-41d4-a716-446655440010
      responses:
        201:
          description: 'The validation decision was recorded.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Correction validation created.'
        400:
          description: 'The correction is no longer pending and cannot be validated.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This correction is no longer pending.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user does not belong to the requested tenant or has no
            linked Tempus employee record.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        409:
          description: 'A validation decision already exists for this correction.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This correction has already been validated.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/validator/pending-requests':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'List employees with pending absence and home office requests (user)'
      operationId: tempusListValidatorPendingRequests
      security:
        -
          bearerAuth: {}
      description: |
        Returns the employees, in scope of the authenticated validator, who have
        pending home office requests, absence requests, or absence removal requests
        awaiting validation. The authenticated user must be a Tempus employee in the
        given PBX; otherwise a 403 is returned.

        The response is a hand-rolled envelope. The `data` object is keyed by the
        employee's telephony extension id. Each value carries the optional
        `home_office`, `absence_requests`, and `absence_removals` sections, populated
        only when the validator has scope for that module and pending records exist.

        The queue is built from the approval rows addressed to the caller, so it
        accounts for approval chains: which step holds the request, watchers, and
        self-approval grants. Every request entry therefore also reports
        `can_decide_now`, `watcher`, `step`, and `awaiting`. Requests at a step below
        the caller's are listed with `can_decide_now: false`: visible, not yet theirs
        to decide.

        `home_office` keeps its three date lists and adds a `requests` array, because
        a home office group is one row per day and the date lists cannot say which
        days the caller may act on.

        Absence entries (`absence_requests`, `absence_removals`) also carry
        `next_availability`: when that employee is back **if this request is approved**,
        next to what the general next-availability answer says today. Home office does
        not — a home office day is governed by a weekly limit, not time off that moves an
        availability date.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 'Page number of the employee list to return.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 10
          description: 'Number of employees to return per page.'
          example: 10
      responses:
        200:
          description: 'OK. Employees with pending requests, keyed by extension id.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: object
                    description: |
                      Object keyed by employee extension id. Each value holds the
                      pending request sections for that employee.
                    additionalProperties:
                      type: object
                      properties:
                        home_office:
                          type: object
                          properties:
                            requested_days:
                              type: array
                              items:
                                type: string
                                format: date
                            requested_removals:
                              type: array
                              items:
                                type: string
                                format: date
                            validated_dates:
                              type: array
                              items:
                                type: string
                                format: date
                            requests:
                              type: array
                              description: |
                                One entry per home office day-row, so the chain state
                                can be read per row rather than per employee.
                              items:
                                allOf:
                                  -
                                    type: object
                                    properties:
                                      id:
                                        type: string
                                        format: uuid
                                      dates:
                                        type: array
                                        description: |
                                          The dates the request covers, read from its per-day booked map. Requests raised since that map held working days only list working days here; older ones can still include a weekend or public holiday inside the range, because those were stored as 0-second entries at the time.
                                        items:
                                          type: string
                                          format: date
                                      sub_type:
                                        type:
                                          - string
                                          - 'null'
                                  -
                                    type: object
                                    description: |
                                      Where a queued request sits in its approval chain, from the point of view of the
                                      validator who asked for the queue.

                                      A request routes through a chain of steps, and only the step currently holding it
                                      may decide. A validator therefore sees requests in two states: theirs to act on
                                      now, and theirs to expect. Both are listed, so a validator on a later step is not
                                      surprised by a request appearing from nowhere once the step below clears.

                                      Requests raised before approval chains existed carry no step: `step` is null and
                                      `can_decide_now` is true, because there is no ladder to wait on.
                                    required:
                                      - can_decide_now
                                      - watcher
                                      - step
                                      - awaiting
                                    properties:
                                      can_decide_now:
                                        type: boolean
                                        description: |
                                          Whether this validator may record a decision on the request right now.
                                          False while the request is at a step below theirs: the decision endpoints
                                          answer 409 in that case, and a client should not offer the action.
                                        example: true
                                      watcher:
                                        type: boolean
                                        description: |
                                          Whether this validator holds the request as a watcher rather than as a step
                                          validator. Watchers sit outside the ladder: they carry no step and, when
                                          granted the power, may settle the request at any point.
                                        example: false
                                      step:
                                        type:
                                          - object
                                          - 'null'
                                        description: |
                                          The step this validator occupies, or null for a watcher and for a request
                                          with no chain. Positions are numbered from 1 in the order the steps are
                                          asked.
                                        required:
                                          - position
                                          - total
                                          - name
                                          - status
                                          - required
                                          - mandatory
                                        properties:
                                          position:
                                            type: integer
                                            description: "This step's place in the chain, counting from 1."
                                            example: 2
                                          total:
                                            type: integer
                                            description: "How many steps the request's chain holds in all."
                                            example: 3
                                          name:
                                            type: string
                                            description: |
                                              The step's name, or a generated "Step n" label when the chain left it
                                              unnamed. Frozen when the request was raised, so renaming a step later
                                              does not relabel requests already in flight.
                                            example: 'Team lead'
                                          status:
                                            type: string
                                            enum:
                                              - pending
                                              - active
                                              - completed
                                              - bypassed
                                              - rejected
                                            description: |
                                              The step's state. `active` is the step holding the request; `pending` has
                                              not been reached; `bypassed` was skipped because the request was settled
                                              above it.
                                            example: active
                                          required:
                                            type: integer
                                            description: 'How many approvals this step needs before it completes.'
                                            example: 2
                                          mandatory:
                                            type: boolean
                                            description: |
                                              Whether this validator must approve for the step to complete. A
                                              must-approve validator holds the step even once its quorum is met.
                                            example: false
                                      awaiting:
                                        type: array
                                        description: |
                                          The validators the request is waiting on right now: those still to answer at
                                          the step holding it, the caller aside. Empty when the caller is the only one
                                          left to answer.
                                        items:
                                          type: string
                                        example:
                                          - 'Muller Jonas'
                        absence_requests:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                              start_format:
                                type:
                                  - string
                                  - 'null'
                              end_format:
                                type:
                                  - string
                                  - 'null'
                              start:
                                type:
                                  - string
                                  - 'null'
                                format: date
                              end:
                                type:
                                  - string
                                  - 'null'
                                format: date
                              comment:
                                type:
                                  - string
                                  - 'null'
                              requested_time:
                                type: string
                              next_availability:
                                oneOf:
                                  -
                                    type: object
                                    description: |
                                      When an employee is next at work **if the request carrying this object goes through**,
                                      next to what the general next-availability answer says today. The validator's view of a
                                      request: no second call, and no cache between the queue and the date.

                                      It is deliberately not the same question as `GET /user/{employee_id}/next-availability`:

                                      - **Anchored at the request, not at today**, so it reports the day *this* booking frees
                                        rather than the next free day counting from now.
                                      - **Counts what has been decided plus this one request.** The base is what has been
                                        signed off (accepted, plus an accepted absence somebody has asked to cancel — still
                                        time off until that cancellation is approved). Other queued requests are left out:
                                        they may be refused, and a date that moves because of a request this validator has not
                                        seen is not one they can act on. (`current` does count every pending row — that
                                        difference is intentional.)
                                      - **A removal reads as a reduction**, so its answer moves *earlier*, often into the past
                                        (`in_past`), which is the signal that the employee is already back.

                                      Absence, illness, special leave and legal holiday only. Home office never carries it: a
                                      home office day is governed by a weekly limit, not time off that moves an availability
                                      date. Neither does a request that can no longer move a date — `rejected`, `canceled` and
                                      `removed`.

                                      **Where it appears:** the absence lists (`/absences`, `/user/{employee_id}/absences`), the
                                      absence-request reads and writes (`/absence-requests`, `/user/{employee_id}/absence-requests`
                                      and its `POST`/`PUT`), `POST /user/{employee_id}/absence-removal-requests`, and both
                                      validator queues (`/validator/pending-requests` — on each `absence_requests[]` /
                                      `absence_removals[]` entry — and v2 `pending-requests/absences`). It is **not** on the
                                      cancel responses (`POST .../absence-requests/{id}/cancel`), which report the outcome of an
                                      employee's own action rather than something a validator is weighing up.

                                      On the resource-backed payloads the key is **omitted** when there is nothing to say; on
                                      the v1 validator queue, whose entries are built by hand, it is always present and `null`
                                      in that case. Both mean the same thing.
                                    required:
                                      - if_approved
                                      - current
                                    properties:
                                      if_approved:
                                        type: object
                                        description: 'Availability as it would stand with this request applied.'
                                        required:
                                          - absent_from
                                          - next_available_date
                                          - next_available_at
                                          - available_now
                                          - in_past
                                          - extends_current_absence
                                          - message
                                        properties:
                                          absent_from:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              First day, today or later, that this request itself takes off. Null when it takes
                                              nothing off in the future: a removal request, or days that have all been and gone.
                                            example: '2026-08-13'
                                          next_available_date:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              The day the employee is back at work under this scenario. Null only when no
                                              working day was found within the search horizon — an employee with no work shift,
                                              or one whose contract has ended.
                                            example: '2026-08-17'
                                          next_available_at:
                                            type:
                                              - string
                                              - 'null'
                                            description: |
                                              Exact moment they are back (`YYYY-MM-DD HH:MM:SS`) when a half day pins one down;
                                              null when only the date is meaningful.
                                            example: null
                                          available_now:
                                            type: boolean
                                            description: |
                                              Whether the employee is at work right now under this scenario. True together with
                                              a future `absent_from` is the ordinary case for a request that starts later.
                                            example: true
                                          in_past:
                                            type: boolean
                                            description: |
                                              True when `next_available_date` is already behind us, i.e. approving this would
                                              not keep anybody away from now on. Render it as "already available" rather than as
                                              a return date.
                                            example: false
                                          extends_current_absence:
                                            type: boolean
                                            description: |
                                              True when this request starts on the very day the employee would otherwise have
                                              come back, so it lengthens the absence already in place rather than opening a
                                              separate one. False for a request with working days in between — show
                                              `absent_from` as well as the return date in that case, or the return date reads as
                                              a contradiction of `available_now`.
                                            example: false
                                          message:
                                            type:
                                              - string
                                              - 'null'
                                            description: |
                                              Ready-to-display line, already covering the three cases: `Available on
                                              2026-08-17`, `Off from 2026-08-13, available on 2026-08-17`, or `Already available
                                              (was back on 2026-08-03)`. Show it as returned.
                                            example: 'Off from 2026-08-13, available on 2026-08-17'
                                      current:
                                        type: object
                                        description: |
                                          Today's general answer, unchanged — the same figure
                                          `GET /user/{employee_id}/next-availability` returns, so the two screens never disagree.
                                        required:
                                          - next_available_date
                                          - message
                                        properties:
                                          next_available_date:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              Next day the employee is available, counting from now. Null when they are
                                              available right now.
                                            example: '2026-08-12'
                                          message:
                                            type:
                                              - string
                                              - 'null'
                                            description: 'Ready-to-display line, or null while the employee is available.'
                                            example: 'Back on 2026-08-12'
                                    example:
                                      if_approved:
                                        absent_from: '2026-08-13'
                                        next_available_date: '2026-08-17'
                                        next_available_at: null
                                        available_now: true
                                        in_past: false
                                        extends_current_absence: false
                                        message: 'Off from 2026-08-13, available on 2026-08-17'
                                      current:
                                        next_available_date: '2026-08-12'
                                        message: 'Back on 2026-08-12'
                                  -
                                    type: 'null'
                                description: |
                                  When this employee is back if this request is approved, next to
                                  what the general answer says today. Always present on absence
                                  entries; `null` for a row that can no longer move a date.
                              validators:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                    ext_id:
                                      type:
                                        - string
                                        - 'null'
                                    comment:
                                      type:
                                        - string
                                        - 'null'
                                    status:
                                      type: string
                              can_decide_now:
                                type: boolean
                              watcher:
                                type: boolean
                              step:
                                type:
                                  - object
                                  - 'null'
                                description: |
                                  The step this validator occupies, or null for a watcher and for a request
                                  with no chain. Positions are numbered from 1 in the order the steps are
                                  asked.
                                required:
                                  - position
                                  - total
                                  - name
                                  - status
                                  - required
                                  - mandatory
                                properties:
                                  position:
                                    type: integer
                                    description: "This step's place in the chain, counting from 1."
                                    example: 2
                                  total:
                                    type: integer
                                    description: "How many steps the request's chain holds in all."
                                    example: 3
                                  name:
                                    type: string
                                    description: |
                                      The step's name, or a generated "Step n" label when the chain left it
                                      unnamed. Frozen when the request was raised, so renaming a step later
                                      does not relabel requests already in flight.
                                    example: 'Team lead'
                                  status:
                                    type: string
                                    enum:
                                      - pending
                                      - active
                                      - completed
                                      - bypassed
                                      - rejected
                                    description: |
                                      The step's state. `active` is the step holding the request; `pending` has
                                      not been reached; `bypassed` was skipped because the request was settled
                                      above it.
                                    example: active
                                  required:
                                    type: integer
                                    description: 'How many approvals this step needs before it completes.'
                                    example: 2
                                  mandatory:
                                    type: boolean
                                    description: |
                                      Whether this validator must approve for the step to complete. A
                                      must-approve validator holds the step even once its quorum is met.
                                    example: false
                              awaiting:
                                type: array
                                items:
                                  type: string
                        absence_removals:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                                format: uuid
                              start_format:
                                type:
                                  - string
                                  - 'null'
                              end_format:
                                type:
                                  - string
                                  - 'null'
                              start:
                                type:
                                  - string
                                  - 'null'
                                format: date
                              end:
                                type:
                                  - string
                                  - 'null'
                                format: date
                              comment:
                                type:
                                  - string
                                  - 'null'
                              requested_time:
                                type: string
                              next_availability:
                                oneOf:
                                  -
                                    type: object
                                    description: |
                                      When an employee is next at work **if the request carrying this object goes through**,
                                      next to what the general next-availability answer says today. The validator's view of a
                                      request: no second call, and no cache between the queue and the date.

                                      It is deliberately not the same question as `GET /user/{employee_id}/next-availability`:

                                      - **Anchored at the request, not at today**, so it reports the day *this* booking frees
                                        rather than the next free day counting from now.
                                      - **Counts what has been decided plus this one request.** The base is what has been
                                        signed off (accepted, plus an accepted absence somebody has asked to cancel — still
                                        time off until that cancellation is approved). Other queued requests are left out:
                                        they may be refused, and a date that moves because of a request this validator has not
                                        seen is not one they can act on. (`current` does count every pending row — that
                                        difference is intentional.)
                                      - **A removal reads as a reduction**, so its answer moves *earlier*, often into the past
                                        (`in_past`), which is the signal that the employee is already back.

                                      Absence, illness, special leave and legal holiday only. Home office never carries it: a
                                      home office day is governed by a weekly limit, not time off that moves an availability
                                      date. Neither does a request that can no longer move a date — `rejected`, `canceled` and
                                      `removed`.

                                      **Where it appears:** the absence lists (`/absences`, `/user/{employee_id}/absences`), the
                                      absence-request reads and writes (`/absence-requests`, `/user/{employee_id}/absence-requests`
                                      and its `POST`/`PUT`), `POST /user/{employee_id}/absence-removal-requests`, and both
                                      validator queues (`/validator/pending-requests` — on each `absence_requests[]` /
                                      `absence_removals[]` entry — and v2 `pending-requests/absences`). It is **not** on the
                                      cancel responses (`POST .../absence-requests/{id}/cancel`), which report the outcome of an
                                      employee's own action rather than something a validator is weighing up.

                                      On the resource-backed payloads the key is **omitted** when there is nothing to say; on
                                      the v1 validator queue, whose entries are built by hand, it is always present and `null`
                                      in that case. Both mean the same thing.
                                    required:
                                      - if_approved
                                      - current
                                    properties:
                                      if_approved:
                                        type: object
                                        description: 'Availability as it would stand with this request applied.'
                                        required:
                                          - absent_from
                                          - next_available_date
                                          - next_available_at
                                          - available_now
                                          - in_past
                                          - extends_current_absence
                                          - message
                                        properties:
                                          absent_from:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              First day, today or later, that this request itself takes off. Null when it takes
                                              nothing off in the future: a removal request, or days that have all been and gone.
                                            example: '2026-08-13'
                                          next_available_date:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              The day the employee is back at work under this scenario. Null only when no
                                              working day was found within the search horizon — an employee with no work shift,
                                              or one whose contract has ended.
                                            example: '2026-08-17'
                                          next_available_at:
                                            type:
                                              - string
                                              - 'null'
                                            description: |
                                              Exact moment they are back (`YYYY-MM-DD HH:MM:SS`) when a half day pins one down;
                                              null when only the date is meaningful.
                                            example: null
                                          available_now:
                                            type: boolean
                                            description: |
                                              Whether the employee is at work right now under this scenario. True together with
                                              a future `absent_from` is the ordinary case for a request that starts later.
                                            example: true
                                          in_past:
                                            type: boolean
                                            description: |
                                              True when `next_available_date` is already behind us, i.e. approving this would
                                              not keep anybody away from now on. Render it as "already available" rather than as
                                              a return date.
                                            example: false
                                          extends_current_absence:
                                            type: boolean
                                            description: |
                                              True when this request starts on the very day the employee would otherwise have
                                              come back, so it lengthens the absence already in place rather than opening a
                                              separate one. False for a request with working days in between — show
                                              `absent_from` as well as the return date in that case, or the return date reads as
                                              a contradiction of `available_now`.
                                            example: false
                                          message:
                                            type:
                                              - string
                                              - 'null'
                                            description: |
                                              Ready-to-display line, already covering the three cases: `Available on
                                              2026-08-17`, `Off from 2026-08-13, available on 2026-08-17`, or `Already available
                                              (was back on 2026-08-03)`. Show it as returned.
                                            example: 'Off from 2026-08-13, available on 2026-08-17'
                                      current:
                                        type: object
                                        description: |
                                          Today's general answer, unchanged — the same figure
                                          `GET /user/{employee_id}/next-availability` returns, so the two screens never disagree.
                                        required:
                                          - next_available_date
                                          - message
                                        properties:
                                          next_available_date:
                                            type:
                                              - string
                                              - 'null'
                                            format: date
                                            description: |
                                              Next day the employee is available, counting from now. Null when they are
                                              available right now.
                                            example: '2026-08-12'
                                          message:
                                            type:
                                              - string
                                              - 'null'
                                            description: 'Ready-to-display line, or null while the employee is available.'
                                            example: 'Back on 2026-08-12'
                                    example:
                                      if_approved:
                                        absent_from: '2026-08-13'
                                        next_available_date: '2026-08-17'
                                        next_available_at: null
                                        available_now: true
                                        in_past: false
                                        extends_current_absence: false
                                        message: 'Off from 2026-08-13, available on 2026-08-17'
                                      current:
                                        next_available_date: '2026-08-12'
                                        message: 'Back on 2026-08-12'
                                  -
                                    type: 'null'
                                description: |
                                  When this employee is back if this request is approved, next to
                                  what the general answer says today. Always present on absence
                                  entries; `null` for a row that can no longer move a date.
                              validators:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                      format: uuid
                                    ext_id:
                                      type:
                                        - string
                                        - 'null'
                                    comment:
                                      type:
                                        - string
                                        - 'null'
                                    status:
                                      type: string
                              can_decide_now:
                                type: boolean
                              watcher:
                                type: boolean
                              step:
                                type:
                                  - object
                                  - 'null'
                                description: |
                                  The step this validator occupies, or null for a watcher and for a request
                                  with no chain. Positions are numbered from 1 in the order the steps are
                                  asked.
                                required:
                                  - position
                                  - total
                                  - name
                                  - status
                                  - required
                                  - mandatory
                                properties:
                                  position:
                                    type: integer
                                    description: "This step's place in the chain, counting from 1."
                                    example: 2
                                  total:
                                    type: integer
                                    description: "How many steps the request's chain holds in all."
                                    example: 3
                                  name:
                                    type: string
                                    description: |
                                      The step's name, or a generated "Step n" label when the chain left it
                                      unnamed. Frozen when the request was raised, so renaming a step later
                                      does not relabel requests already in flight.
                                    example: 'Team lead'
                                  status:
                                    type: string
                                    enum:
                                      - pending
                                      - active
                                      - completed
                                      - bypassed
                                      - rejected
                                    description: |
                                      The step's state. `active` is the step holding the request; `pending` has
                                      not been reached; `bypassed` was skipped because the request was settled
                                      above it.
                                    example: active
                                  required:
                                    type: integer
                                    description: 'How many approvals this step needs before it completes.'
                                    example: 2
                                  mandatory:
                                    type: boolean
                                    description: |
                                      Whether this validator must approve for the step to complete. A
                                      must-approve validator holds the step even once its quorum is met.
                                    example: false
                              awaiting:
                                type: array
                                items:
                                  type: string
                  pagination:
                    type: object
                    required:
                      - page
                      - total_pages
                      - total
                      - per_page
                    properties:
                      page:
                        type: integer
                        example: 1
                      total_pages:
                        type: integer
                        example: 3
                      total:
                        type: integer
                        example: 24
                      per_page:
                        type: integer
                        example: 10
              example:
                data:
                  1042:
                    home_office:
                      requested_days:
                        - '2024-03-04'
                      requested_removals: {}
                      validated_dates: {}
                      requests:
                        -
                          id: 550e8400-e29b-41d4-a716-446655440030
                          dates:
                            - '2024-03-04'
                          sub_type: null
                          can_decide_now: true
                          watcher: false
                          step:
                            position: 1
                            total: 2
                            name: 'Team lead'
                            status: active
                            required: 1
                            mandatory: false
                          awaiting: {}
                    absence_requests:
                      -
                        id: 550e8400-e29b-41d4-a716-446655440010
                        start_format: '04 Mar 09:00'
                        end_format: '06 Mar 18:00'
                        start: '2024-03-04'
                        end: '2024-03-06'
                        comment: 'Family trip'
                        requested_time: 24h
                        next_availability:
                          if_approved:
                            absent_from: '2024-03-04'
                            next_available_date: '2024-03-07'
                            next_available_at: null
                            available_now: true
                            in_past: false
                            extends_current_absence: false
                            message: 'Off from 2024-03-04, available on 2024-03-07'
                          current:
                            next_available_date: null
                            message: null
                        validators:
                          -
                            id: 550e8400-e29b-41d4-a716-446655440020
                            ext_id: '1099'
                            comment: null
                            status: pending
                        can_decide_now: false
                        watcher: false
                        step:
                          position: 2
                          total: 2
                          name: Management
                          status: pending
                          required: 1
                          mandatory: false
                        awaiting:
                          - 'Muller Jonas'
                    absence_removals: {}
                pagination:
                  page: 1
                  total_pages: 3
                  total: 24
                  per_page: 10
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user is not part of the PBX or is not a
            Tempus employee in this tenant.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/validator/pending-corrections':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'List pending time point corrections in the validator scope (user)'
      operationId: tempusListValidatorPendingCorrections
      security:
        -
          bearerAuth: {}
      description: |
        Returns the pending time point correction requests raised by employees who
        fall within the authenticated validator's correction scope. The
        authenticated user must be a Tempus employee in the given PBX; otherwise a
        403 is returned.

        The response is a hand-rolled envelope: a `data` array of correction objects
        plus a `pagination` block. Each correction is serialized by the V1
        `PendingCorrectionResource`.

        The queue is built from the approval rows addressed to the caller, so it
        accounts for approval chains. Each correction therefore also reports
        `can_decide_now`, `watcher`, `step`, and `awaiting`: a correction at a step
        below the caller's is listed with `can_decide_now: false`, visible but not yet
        theirs to decide.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 'Page number of the corrections list to return.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 10
          description: 'Number of corrections to return per page.'
          example: 10
      responses:
        200:
          description: 'OK. Paginated list of pending corrections.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      allOf:
                        -
                          $ref: '#/components/schemas/TempusPendingCorrection'
                        -
                          type: object
                          description: |
                            Where a queued request sits in its approval chain, from the point of view of the
                            validator who asked for the queue.

                            A request routes through a chain of steps, and only the step currently holding it
                            may decide. A validator therefore sees requests in two states: theirs to act on
                            now, and theirs to expect. Both are listed, so a validator on a later step is not
                            surprised by a request appearing from nowhere once the step below clears.

                            Requests raised before approval chains existed carry no step: `step` is null and
                            `can_decide_now` is true, because there is no ladder to wait on.
                          required:
                            - can_decide_now
                            - watcher
                            - step
                            - awaiting
                          properties:
                            can_decide_now:
                              type: boolean
                              description: |
                                Whether this validator may record a decision on the request right now.
                                False while the request is at a step below theirs: the decision endpoints
                                answer 409 in that case, and a client should not offer the action.
                              example: true
                            watcher:
                              type: boolean
                              description: |
                                Whether this validator holds the request as a watcher rather than as a step
                                validator. Watchers sit outside the ladder: they carry no step and, when
                                granted the power, may settle the request at any point.
                              example: false
                            step:
                              type:
                                - object
                                - 'null'
                              description: |
                                The step this validator occupies, or null for a watcher and for a request
                                with no chain. Positions are numbered from 1 in the order the steps are
                                asked.
                              required:
                                - position
                                - total
                                - name
                                - status
                                - required
                                - mandatory
                              properties:
                                position:
                                  type: integer
                                  description: "This step's place in the chain, counting from 1."
                                  example: 2
                                total:
                                  type: integer
                                  description: "How many steps the request's chain holds in all."
                                  example: 3
                                name:
                                  type: string
                                  description: |
                                    The step's name, or a generated "Step n" label when the chain left it
                                    unnamed. Frozen when the request was raised, so renaming a step later
                                    does not relabel requests already in flight.
                                  example: 'Team lead'
                                status:
                                  type: string
                                  enum:
                                    - pending
                                    - active
                                    - completed
                                    - bypassed
                                    - rejected
                                  description: |
                                    The step's state. `active` is the step holding the request; `pending` has
                                    not been reached; `bypassed` was skipped because the request was settled
                                    above it.
                                  example: active
                                required:
                                  type: integer
                                  description: 'How many approvals this step needs before it completes.'
                                  example: 2
                                mandatory:
                                  type: boolean
                                  description: |
                                    Whether this validator must approve for the step to complete. A
                                    must-approve validator holds the step even once its quorum is met.
                                  example: false
                            awaiting:
                              type: array
                              description: |
                                The validators the request is waiting on right now: those still to answer at
                                the step holding it, the caller aside. Empty when the caller is the only one
                                left to answer.
                              items:
                                type: string
                              example:
                                - 'Muller Jonas'
                  pagination:
                    type: object
                    required:
                      - page
                      - total_pages
                      - total
                      - per_page
                    properties:
                      page:
                        type: integer
                        example: 1
                      total_pages:
                        type: integer
                        example: 4
                      total:
                        type: integer
                        example: 38
                      per_page:
                        type: integer
                        example: 10
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user is not part of the PBX or is not a
            Tempus employee in this tenant.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/validator/pending-corrections/{correction_id}/details':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'Get the time points behind a pending correction (user)'
      operationId: tempusGetValidatorPendingCorrectionDetails
      security:
        -
          bearerAuth: {}
      description: |
        Returns the day's time points for the employee tied to a single pending
        correction, giving the validator the surrounding clock events for context.
        The correction must belong to an employee within the authenticated
        validator's correction scope; otherwise a 403 is returned. A 400 is returned
        when the correction has neither a new nor an old time, or its requester has
        no linked user.

        The response is a bare array of time point objects (not wrapped in `data`),
        each serialized by the V1 `PendingCorrectionDetailsResource`.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: correction_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the pending correction to inspect.'
          example: 550e8400-e29b-41d4-a716-446655440010
      responses:
        200:
          description: "OK. Time points for the correction's day."
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TempusPendingCorrectionDetails'
        400:
          description: |
            Bad request. The correction has no usable date, or its requester has no
            linked user account.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Something went wrong.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user is not part of the PBX, is not a
            Tempus employee in this tenant, or the correction is outside their
            validation scope.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/validator-permissions':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'Get the validator permissions for an employee (user)'
      operationId: tempusGetValidatorPermissions
      deprecated: true
      security:
        -
          bearerAuth: {}
      description: |
        Deprecated: these per-module capability flags are now returned inline on the
        user profile under the `validator.permissions` block
        (`GET /{pbx_id}/user/{employee_id}/profile`). Prefer that; this endpoint is
        kept for backward compatibility.

        Returns the validation capabilities the given employee holds: whether they
        can validate absences, home office, and corrections, whether they manage
        schedules, and whether they have calendar access. The employee must belong
        to the authenticated user (their `user_id` must match the requester) and to
        the PBX; otherwise a 403 is returned. A 404 is returned when the employee
        does not exist in the tenant.

        The response is a flat object of booleans, not wrapped in `data`.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the Tempus employee.'
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: "OK. The employee's validation capabilities."
          content:
            application/json:
              schema:
                type: object
                required:
                  - absence_validation
                  - home_office_validation
                  - correction_validation
                  - schedules_management
                  - calendar_access
                properties:
                  absence_validation:
                    type: boolean
                    description: 'Whether the employee can validate absence requests.'
                  home_office_validation:
                    type: boolean
                    description: 'Whether the employee can validate home office requests.'
                  correction_validation:
                    type: boolean
                    description: 'Whether the employee can validate time point corrections.'
                  schedules_management:
                    type: boolean
                    description: 'Whether the employee can manage schedules.'
                  calendar_access:
                    type: boolean
                    description: 'Whether the employee has calendar access.'
              example:
                absence_validation: true
                home_office_validation: true
                correction_validation: true
                schedules_management: false
                calendar_access: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user is not part of the PBX, or the
            employee does not belong to the authenticated user.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/validator/scope':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusValidators
      summary: 'Get the validator scope (employees the authenticated user can validate)'
      operationId: getTempusValidatorScope
      deprecated: true
      description: |
        Deprecated: the caller's validator scope is now returned inline on their user
        profile under the `validator` block (`GET /{pbx_id}/user/{employee_id}/profile`),
        which carries the same per-module scope plus the consultable companies,
        departments and employees. Prefer that; this endpoint is kept for
        backward compatibility.

        Returns the tempus validator scope identified by the path parameter. Multi-tenant scoping is
        enforced: the caller can only fetch resources within their own PBX.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant'
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          description: |
            OK. The response is a flat object keyed by validator module name
            (`holiday_requests`, `time_point_corrections_requests`, etc.). Each
            module entry says whether the authenticated user is a validator for
            that module and lists the employees in their scope.
          content:
            application/json:
              schema:
                type: object
                description: |
                  Object keyed by validator module name. NOT wrapped in `data`.
                  Module names come from `ValidatorRule::MODULE_*`.
                additionalProperties:
                  type: object
                  required:
                    - enabled
                    - targets
                  properties:
                    enabled:
                      type: boolean
                      description: 'Whether the authenticated user can validate this module'
                    targets:
                      type: array
                      description: 'Employees in scope for this module'
                      items:
                        type: object
                        properties:
                          user_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
                          employee_id:
                            type: string
                            format: uuid
                          extension_id:
                            type:
                              - string
                              - 'null'
                            format: uuid
              example:
                holiday_requests:
                  enabled: true
                  targets:
                    -
                      user_id: 550e8400-e29b-41d4-a716-446655440010
                      employee_id: 550e8400-e29b-41d4-a716-446655440011
                      extension_id: 550e8400-e29b-41d4-a716-446655440012
                time_point_corrections_requests:
                  enabled: true
                  targets:
                    -
                      user_id: 550e8400-e29b-41d4-a716-446655440020
                      employee_id: 550e8400-e29b-41d4-a716-446655440021
                      extension_id: 550e8400-e29b-41d4-a716-446655440022
                home_office_requests:
                  enabled: false
                  targets: {}
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/validator/change-employee-status':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusValidators
      summary: "Change a scoped employee's current status as a validator (user)"
      operationId: tempusChangeValidatorEmployeeStatus
      security:
        -
          bearerAuth: {}
      description: |
        Sets the current Tempus status (and optional sub-statuses) of an employee on
        behalf of a validator. The authenticated user must be a Tempus employee in
        the PBX and must hold correction scope over the target employee; otherwise a
        403 is returned. A 404 is returned when no employee matches the given
        `user_id` in the tenant. A validator may assign any status, not only the ones
        in the employee's active layout.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 'UUID of the PBX tenant.'
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_id
                - status_id
              properties:
                user_id:
                  type: string
                  format: uuid
                  description: 'UUID of the target user whose status is being changed.'
                  example: 550e8400-e29b-41d4-a716-446655440030
                status_id:
                  type: string
                  format: uuid
                  description: 'UUID of the Tempus status to assign.'
                  example: 550e8400-e29b-41d4-a716-446655440031
                sub_status_ids:
                  type: array
                  description: |
                    Optional UUIDs of sub-statuses to assign. Each must belong to the
                    chosen status.
                  items:
                    type: string
                    format: uuid
                  example:
                    - 550e8400-e29b-41d4-a716-446655440032
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free-form comment recorded with the change.'
                  example: 'Manual status set by validator'
      responses:
        200:
          description: 'OK. The status that was applied.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - user_id
                  - status_id
                  - sub_status_ids
                properties:
                  user_id:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440030
                  status_id:
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440031
                  sub_status_ids:
                    type: array
                    items:
                      type: string
                      format: uuid
                    example:
                      - 550e8400-e29b-41d4-a716-446655440032
              example:
                user_id: 550e8400-e29b-41d4-a716-446655440030
                status_id: 550e8400-e29b-41d4-a716-446655440031
                sub_status_ids:
                  - 550e8400-e29b-41d4-a716-446655440032
        400:
          description: |
            Bad request. The status change failed; the body carries an `errors`
            array describing the reasons.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The status change failed.'
                  errors:
                    type: array
                    items:
                      type: string
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The authenticated user is not part of the PBX, is not a
            Tempus employee in this tenant, or has no correction scope over the
            target employee.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "You are not allowed to change this employee's status."
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/v2/{pbx}/employee/{employee}/profile':
    get:
      tags:
        - TempusProfile
      summary: 'Get your own Tempus profile (user)'
      operationId: tempusV2ShowEmployeeProfile
      security:
        -
          bearerAuth: {}
      servers:
        -
          url: 'https://cockpit.voxbi.com/tempus/api'
          description: 'Tempus production API server'
        -
          url: 'https://staging-cockpit.voxbi.com/tempus/api'
          description: 'Tempus staging API server'
        -
          url: 'https://dev-cockpit.voxbi.com/tempus/api'
          description: 'Tempus dev API server'
      description: |
        The caller's own Tempus profile: their active contract, balances, home office
        settings, preferences, and what they validate.

        Same payload as `GET /tempus/api/v1/{pbx_id}/user/{employee_id}/profile` with one
        difference, which is why it is versioned: the `validator` block is the v2 shape. It
        always has the same keys (`is_validator`, `permissions`, `pending`) instead of being
        an object or null, and it drops the `companies`, `departments` and `employees` lists,
        which approval chains cannot produce cheaply. That roster is on
        `GET /tempus/api/v1/{pbx_id}/validator/employees`.

        The path says `employee`, not v1's `user`: the subject is a Tempus employee record,
        and v1 passed an employee id to a segment named `user`.

        422 when the employee has no active contract, since almost every figure in the
        payload is derived from one.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: "OK. The employee's profile."
          content:
            application/json:
              schema:
                allOf:
                  -
                    $ref: '#/components/schemas/TempusUserProfile'
                  -
                    type: object
                    properties:
                      validator:
                        type: object
                        description: |
                          What an employee validates, and how much is waiting on them.

                          One shape whether or not they are a validator: `is_validator` is the flag, and a
                          non-validator gets all-false permissions with zero counts. A payload that changed shape
                          for the answer "no" would make that a special case at every call site.

                          Not wrapped in `data`: one object is returned and there is no collection envelope for it
                          to be consistent with.

                          What it deliberately does not carry: the companies, departments and employees a
                          validator covers, which v1's profile block did. With approval chains a validator's place
                          is a position in each requester's own chain, resolved through that person's contract, so
                          that roster is not a flat set this can produce cheaply. It lives on
                          `GET /tempus/api/v1/{pbx_id}/validator/employees`.
                        required:
                          - is_validator
                          - permissions
                          - pending
                        properties:
                          is_validator:
                            type: boolean
                            description: |
                              Whether they hold any validator role at all, which is the signal for whether to
                              offer a validator section. True when any chain that reaches somebody names them,
                              as a step validator or as a watcher, for at least one request type. A chain that is
                              staffed but scoped to nobody does not count, so a half-built chain cannot light up a
                              section with nothing behind it.
                            example: true
                          permissions:
                            type: object
                            description: 'Which request types they are asked to decide.'
                            required:
                              - absence_requests
                              - home_office_requests
                              - time_point_corrections
                              - schedule_assignment_requests
                            properties:
                              absence_requests:
                                type: boolean
                                example: true
                              home_office_requests:
                                type: boolean
                                example: true
                              time_point_corrections:
                                type: boolean
                                example: false
                              schedule_assignment_requests:
                                type: boolean
                                example: false
                          pending:
                            type: object
                            description: |
                              How many requests of each type are waiting on them right now, counted from the
                              approval rows addressed to them, so it matches the queue endpoints exactly. An
                              all-zero map means only that nothing is waiting today: somebody with an empty queue
                              is still a validator, so gate the section on `is_validator` and use these for badges
                              or to skip a part that would open empty.

                              The queue for each: `absence_requests` is `pending-requests/absences`,
                              `home_office_requests` is `pending-requests/home-office`, and
                              `time_point_corrections` is `pending-requests/time-point-corrections`.
                              `schedule_assignment_requests` is always 0: schedule assignment is direct
                              management, not a request queue.
                            required:
                              - absence_requests
                              - home_office_requests
                              - time_point_corrections
                              - schedule_assignment_requests
                            properties:
                              absence_requests:
                                type: integer
                                example: 3
                              home_office_requests:
                                type: integer
                                example: 1
                              time_point_corrections:
                                type: integer
                                example: 0
                              schedule_assignment_requests:
                                type: integer
                                example: 0
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
        422:
          description: |
            Unprocessable. The employee has no active contract, so there is no profile to
            assemble.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'No active contract found for this employee.'
  '/v2/{pbx}/employee/{employee}/validator':
    get:
      tags:
        - TempusValidators
      summary: "Get an employee's validator role and queue counts (user)"
      operationId: tempusV2ShowEmployeeValidator
      security:
        -
          bearerAuth: {}
      servers:
        -
          url: 'https://cockpit.voxbi.com/tempus/api'
          description: 'Tempus production API server'
        -
          url: 'https://staging-cockpit.voxbi.com/tempus/api'
          description: 'Tempus staging API server'
        -
          url: 'https://dev-cockpit.voxbi.com/tempus/api'
          description: 'Tempus dev API server'
      description: |
        Whether this employee holds a validator role, which request types are theirs,
        and how much is queued for them.

        Replaces the `validator` block of `GET /tempus/api/v1/{pbx_id}/user/{employee_id}/profile`.
        That block also carried the companies, departments and employees the validator
        covered; with approval chains that roster is not a flat set (a validator's place
        is a position in each requester's own chain, resolved through that person's
        contract), so it is not repeated here. For the roster use
        `GET /tempus/api/v1/{pbx_id}/validator/employees`; for the work itself use the
        per-type queues under `employee/{employee}/pending-requests/`: `absences`,
        `home-office` and `corrections`.

        The same block is on `GET /v2/{pbx}/employee/{employee}/profile`, so a screen that
        already fetches the profile needs no second call. This endpoint exists for the
        opposite case: deciding whether to offer a validator section is one boolean, and
        should not require the whole profile payload.

        Readable for your own employee record only: asking for another employee returns
        403, since how someone else's validator duties are staffed is not theirs to read.

        Note the path says `employee`, not `user` as v1 did: the subject is a Tempus
        employee record, and v1 passed an employee id to a segment named `user`.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'OK. Always this shape, whether or not they are a validator.'
          content:
            application/json:
              schema:
                type: object
                description: |
                  What an employee validates, and how much is waiting on them.

                  One shape whether or not they are a validator: `is_validator` is the flag, and a
                  non-validator gets all-false permissions with zero counts. A payload that changed shape
                  for the answer "no" would make that a special case at every call site.

                  Not wrapped in `data`: one object is returned and there is no collection envelope for it
                  to be consistent with.

                  What it deliberately does not carry: the companies, departments and employees a
                  validator covers, which v1's profile block did. With approval chains a validator's place
                  is a position in each requester's own chain, resolved through that person's contract, so
                  that roster is not a flat set this can produce cheaply. It lives on
                  `GET /tempus/api/v1/{pbx_id}/validator/employees`.
                required:
                  - is_validator
                  - permissions
                  - pending
                properties:
                  is_validator:
                    type: boolean
                    description: |
                      Whether they hold any validator role at all, which is the signal for whether to
                      offer a validator section. True when any chain that reaches somebody names them,
                      as a step validator or as a watcher, for at least one request type. A chain that is
                      staffed but scoped to nobody does not count, so a half-built chain cannot light up a
                      section with nothing behind it.
                    example: true
                  permissions:
                    type: object
                    description: 'Which request types they are asked to decide.'
                    required:
                      - absence_requests
                      - home_office_requests
                      - time_point_corrections
                      - schedule_assignment_requests
                    properties:
                      absence_requests:
                        type: boolean
                        example: true
                      home_office_requests:
                        type: boolean
                        example: true
                      time_point_corrections:
                        type: boolean
                        example: false
                      schedule_assignment_requests:
                        type: boolean
                        example: false
                  pending:
                    type: object
                    description: |
                      How many requests of each type are waiting on them right now, counted from the
                      approval rows addressed to them, so it matches the queue endpoints exactly. An
                      all-zero map means only that nothing is waiting today: somebody with an empty queue
                      is still a validator, so gate the section on `is_validator` and use these for badges
                      or to skip a part that would open empty.

                      The queue for each: `absence_requests` is `pending-requests/absences`,
                      `home_office_requests` is `pending-requests/home-office`, and
                      `time_point_corrections` is `pending-requests/time-point-corrections`.
                      `schedule_assignment_requests` is always 0: schedule assignment is direct
                      management, not a request queue.
                    required:
                      - absence_requests
                      - home_office_requests
                      - time_point_corrections
                      - schedule_assignment_requests
                    properties:
                      absence_requests:
                        type: integer
                        example: 3
                      home_office_requests:
                        type: integer
                        example: 1
                      time_point_corrections:
                        type: integer
                        example: 0
                      schedule_assignment_requests:
                        type: integer
                        example: 0
              examples:
                validator:
                  summary: 'Validates absences and home office, three absences waiting'
                  value:
                    is_validator: true
                    permissions:
                      absence_requests: true
                      home_office_requests: true
                      time_point_corrections: false
                      schedule_assignment_requests: false
                    pending:
                      absence_requests: 3
                      home_office_requests: 0
                      time_point_corrections: 0
                      schedule_assignment_requests: 0
                notAValidator:
                  summary: 'Validates nothing'
                  value:
                    is_validator: false
                    permissions:
                      absence_requests: false
                      home_office_requests: false
                      time_point_corrections: false
                      schedule_assignment_requests: false
                    pending:
                      absence_requests: 0
                      home_office_requests: 0
                      time_point_corrections: 0
                      schedule_assignment_requests: 0
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
  '/v2/{pbx}/employee/{employee}/pending-requests/absences':
    get:
      tags:
        - TempusValidators
      summary: 'List the absence requests waiting on you to decide (user)'
      operationId: tempusV2ListPendingAbsenceRequests
      security:
        -
          bearerAuth: {}
      servers:
        -
          url: 'https://cockpit.voxbi.com/tempus/api'
          description: 'Tempus production API server'
        -
          url: 'https://staging-cockpit.voxbi.com/tempus/api'
          description: 'Tempus staging API server'
        -
          url: 'https://dev-cockpit.voxbi.com/tempus/api'
          description: 'Tempus dev API server'
      description: |
        The absence, illness and special-leave requests this employee is asked to decide,
        newest first, one entry per request. Requests to remove already approved days are
        included, marked `sub_type: removal`.

        Read off the approval rows addressed to them, so approval chains are honoured
        exactly as the decision endpoints honour them: which step holds the request,
        watchers, self-approval grants, and restarts. Requests at a step below theirs are
        included with `can_decide_now: false`, so a validator further up a chain sees what
        is coming rather than having it appear from nowhere.

        Your own employee record only: another employee's id returns 403, since a queue is
        built from rows addressed to one person.

        One endpoint per request type, matching how the work is looked at: a screen showing
        one type pages that type, instead of over-fetching a mixed feed and filtering it.
        The sibling queues are `pending-requests/absences`, `pending-requests/home-office`
        and `pending-requests/time-point-corrections`; `GET /v2/{pbx}/employee/{employee}/validator`
        reports how many are waiting in each.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 'Page number to return.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 10
          description: 'Number of entries per page.'
          example: 10
        -
          name: 'filter[requester_id]'
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: |
            Narrow the queue to one person who raised requests. Named `requester_id` rather than
            `employee_id` because the employee in the path is the validator: these routes have two
            employees in play. A requester you hold no rows on yields an empty page rather than a
            403, since nothing was hidden from you.
          example: 550e8400-e29b-41d4-a716-446655440002
      responses:
        200:
          description: 'OK. Paginated absence requests waiting on this employee.'
          content:
            application/json:
              schema:
                type: object
                description: |
                  A page of requests waiting on one validator, one entry per request.

                  Each entry is the v2 transaction payload plus where the caller stands in that
                  request's approval chain. The envelope is hand-rolled (`data` plus `pagination`), not
                  Laravel's paginator shape. Entries are newest first.
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      allOf:
                        -
                          type: object
                          description: |
                            A request stored as a Tempus transaction: absence, illness, special leave, legal
                            holiday, home office, and removals of any of them.

                            v2 of the payload. What changed from v1 and why:

                            - **People are employees, never extensions.** v1 carried `ext_id`, a telephony
                              extension id, on a Tempus record. It was the wrong identifier for this domain (an
                              employee need not have an extension, and the field silently fell back to the
                              employee id when they did not, so it meant two different things) and it cost two
                              queries per row to produce. Everyone here is identified by `employee_id`.
                            - **One identifier per thing.** v1 repeated one value as `employee_id`,
                              `requester_id` and `creator_id`, and the request id as both `id` and
                              `absence_request_id`. Also gone: `mxvp_user_id`, which was the pbx id under a name
                              from another system, and `holiday_id`, which was always null.
                            - **Stored values, not translated ones.** v1 renamed `absence` to `legal` and
                              `approved` to `accepted` on the way out, so a client could not match what it read
                              against what it sent, nor against the request type names the approval chain uses.
                          required:
                            - id
                            - type
                            - status
                            - employee_id
                            - dates
                            - requested_time
                            - requested_seconds
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: |
                                The request id, which the decision endpoints take. For home office this is one
                                day-row: a request covering a week is stored as a row per day, each decided on
                                its own.
                              example: 550e8400-e29b-41d4-a716-446655440010
                            type:
                              type: string
                              enum:
                                - absence
                                - illness
                                - special
                                - legal_holiday
                                - home_office
                              description: 'The stored request type, not a renamed one.'
                              example: absence
                            sub_type:
                              type:
                                - string
                                - 'null'
                              description: |
                                `removal` when the request asks to take back days that were already approved,
                                otherwise null.
                              example: null
                            status:
                              type: string
                              enum:
                                - pending
                                - approved
                                - rejected
                                - cancelled
                                - pending_removal
                              description: 'The stored status.'
                              example: pending
                            employee_id:
                              type: string
                              format: uuid
                              description: 'The employee the request is for, whose balance and calendar it moves.'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            employee:
                              type:
                                - object
                                - 'null'
                              description: |
                                The same employee, by name, when the relation was loaded. Present on the validator
                                queues, absent where the endpoint does not load it.
                              properties:
                                employee_id:
                                  type: string
                                  format: uuid
                                first_name:
                                  type:
                                    - string
                                    - 'null'
                                last_name:
                                  type:
                                    - string
                                    - 'null'
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Muller Anna'
                            requested_by:
                              type:
                                - object
                                - 'null'
                              description: |
                                Who raised the request, when that is somebody other than the employee it is for
                                (raised on their behalf). Null for the ordinary case of raising your own, so a
                                client can show provenance only when there is any.
                              properties:
                                employee_id:
                                  type: string
                                  format: uuid
                                first_name:
                                  type:
                                    - string
                                    - 'null'
                                last_name:
                                  type:
                                    - string
                                    - 'null'
                                name:
                                  type:
                                    - string
                                    - 'null'
                            company_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            start:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2026-03-04T00:00:00+00:00'
                            end:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2026-03-06T00:00:00+00:00'
                            dates:
                              type: array
                              description: |
                                The days actually asked for, which is what to read rather than the range: a
                                request can skip days.
                              items:
                                type: string
                                format: date
                              example:
                                - '2026-03-04'
                                - '2026-03-05'
                            requested_time:
                              type: object
                              description: 'Seconds asked for per day, keyed by date.'
                              additionalProperties:
                                type: integer
                              example:
                                '2026-03-04': 28800
                                '2026-03-05': 28800
                            requested_seconds:
                              type: integer
                              description: 'The sum of `requested_time`, for convenience.'
                              example: 57600
                            next_availability:
                              type: object
                              description: |
                                When an employee is next at work **if the request carrying this object goes through**,
                                next to what the general next-availability answer says today. The validator's view of a
                                request: no second call, and no cache between the queue and the date.

                                It is deliberately not the same question as `GET /user/{employee_id}/next-availability`:

                                - **Anchored at the request, not at today**, so it reports the day *this* booking frees
                                  rather than the next free day counting from now.
                                - **Counts what has been decided plus this one request.** The base is what has been
                                  signed off (accepted, plus an accepted absence somebody has asked to cancel — still
                                  time off until that cancellation is approved). Other queued requests are left out:
                                  they may be refused, and a date that moves because of a request this validator has not
                                  seen is not one they can act on. (`current` does count every pending row — that
                                  difference is intentional.)
                                - **A removal reads as a reduction**, so its answer moves *earlier*, often into the past
                                  (`in_past`), which is the signal that the employee is already back.

                                Absence, illness, special leave and legal holiday only. Home office never carries it: a
                                home office day is governed by a weekly limit, not time off that moves an availability
                                date. Neither does a request that can no longer move a date — `rejected`, `canceled` and
                                `removed`.

                                **Where it appears:** the absence lists (`/absences`, `/user/{employee_id}/absences`), the
                                absence-request reads and writes (`/absence-requests`, `/user/{employee_id}/absence-requests`
                                and its `POST`/`PUT`), `POST /user/{employee_id}/absence-removal-requests`, and both
                                validator queues (`/validator/pending-requests` — on each `absence_requests[]` /
                                `absence_removals[]` entry — and v2 `pending-requests/absences`). It is **not** on the
                                cancel responses (`POST .../absence-requests/{id}/cancel`), which report the outcome of an
                                employee's own action rather than something a validator is weighing up.

                                On the resource-backed payloads the key is **omitted** when there is nothing to say; on
                                the v1 validator queue, whose entries are built by hand, it is always present and `null`
                                in that case. Both mean the same thing.
                              required:
                                - if_approved
                                - current
                              properties:
                                if_approved:
                                  type: object
                                  description: 'Availability as it would stand with this request applied.'
                                  required:
                                    - absent_from
                                    - next_available_date
                                    - next_available_at
                                    - available_now
                                    - in_past
                                    - extends_current_absence
                                    - message
                                  properties:
                                    absent_from:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        First day, today or later, that this request itself takes off. Null when it takes
                                        nothing off in the future: a removal request, or days that have all been and gone.
                                      example: '2026-08-13'
                                    next_available_date:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        The day the employee is back at work under this scenario. Null only when no
                                        working day was found within the search horizon — an employee with no work shift,
                                        or one whose contract has ended.
                                      example: '2026-08-17'
                                    next_available_at:
                                      type:
                                        - string
                                        - 'null'
                                      description: |
                                        Exact moment they are back (`YYYY-MM-DD HH:MM:SS`) when a half day pins one down;
                                        null when only the date is meaningful.
                                      example: null
                                    available_now:
                                      type: boolean
                                      description: |
                                        Whether the employee is at work right now under this scenario. True together with
                                        a future `absent_from` is the ordinary case for a request that starts later.
                                      example: true
                                    in_past:
                                      type: boolean
                                      description: |
                                        True when `next_available_date` is already behind us, i.e. approving this would
                                        not keep anybody away from now on. Render it as "already available" rather than as
                                        a return date.
                                      example: false
                                    extends_current_absence:
                                      type: boolean
                                      description: |
                                        True when this request starts on the very day the employee would otherwise have
                                        come back, so it lengthens the absence already in place rather than opening a
                                        separate one. False for a request with working days in between — show
                                        `absent_from` as well as the return date in that case, or the return date reads as
                                        a contradiction of `available_now`.
                                      example: false
                                    message:
                                      type:
                                        - string
                                        - 'null'
                                      description: |
                                        Ready-to-display line, already covering the three cases: `Available on
                                        2026-08-17`, `Off from 2026-08-13, available on 2026-08-17`, or `Already available
                                        (was back on 2026-08-03)`. Show it as returned.
                                      example: 'Off from 2026-08-13, available on 2026-08-17'
                                current:
                                  type: object
                                  description: |
                                    Today's general answer, unchanged — the same figure
                                    `GET /user/{employee_id}/next-availability` returns, so the two screens never disagree.
                                  required:
                                    - next_available_date
                                    - message
                                  properties:
                                    next_available_date:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        Next day the employee is available, counting from now. Null when they are
                                        available right now.
                                      example: '2026-08-12'
                                    message:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Ready-to-display line, or null while the employee is available.'
                                      example: 'Back on 2026-08-12'
                              example:
                                if_approved:
                                  absent_from: '2026-08-13'
                                  next_available_date: '2026-08-17'
                                  next_available_at: null
                                  available_now: true
                                  in_past: false
                                  extends_current_absence: false
                                  message: 'Off from 2026-08-13, available on 2026-08-17'
                                current:
                                  next_available_date: '2026-08-12'
                                  message: 'Back on 2026-08-12'
                            comment:
                              type:
                                - string
                                - 'null'
                              description: "The requester's note."
                              example: 'Family trip'
                            created:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            modified:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            validators:
                              type: array
                              description: |
                                Everyone this request asks, with their answer so far and where they sit, when the
                                approvals relation was loaded. Rows superseded by a restarted chain are left out:
                                they record what a previous round asked and are not people still to answer.
                              items:
                                type: object
                                properties:
                                  employee_id:
                                    type:
                                      - string
                                      - 'null'
                                    format: uuid
                                  name:
                                    type: string
                                    description: |
                                      The name frozen on the row when it was written, so a validator who has since
                                      been deleted still reads correctly.
                                    example: 'Lemaire Farid'
                                  status:
                                    type: string
                                    enum:
                                      - pending
                                      - accepted
                                      - rejected
                                  comment:
                                    type:
                                      - string
                                      - 'null'
                                  step_position:
                                    type:
                                      - integer
                                      - 'null'
                                    description: |
                                      Their rung in the chain, or null for a watcher, who sits outside the ladder.
                                    example: 1
                                  watcher:
                                    type: boolean
                                  mandatory:
                                    type: boolean
                                    description: |
                                      Whether their approval is required for the step to complete, whatever its
                                      quorum.
                        -
                          type: object
                          description: |
                            Where a queued request sits in its approval chain, from the point of view of the
                            validator who asked for the queue.

                            A request routes through a chain of steps, and only the step currently holding it
                            may decide. A validator therefore sees requests in two states: theirs to act on
                            now, and theirs to expect. Both are listed, so a validator on a later step is not
                            surprised by a request appearing from nowhere once the step below clears.

                            Requests raised before approval chains existed carry no step: `step` is null and
                            `can_decide_now` is true, because there is no ladder to wait on.
                          required:
                            - can_decide_now
                            - watcher
                            - step
                            - awaiting
                          properties:
                            can_decide_now:
                              type: boolean
                              description: |
                                Whether this validator may record a decision on the request right now.
                                False while the request is at a step below theirs: the decision endpoints
                                answer 409 in that case, and a client should not offer the action.
                              example: true
                            watcher:
                              type: boolean
                              description: |
                                Whether this validator holds the request as a watcher rather than as a step
                                validator. Watchers sit outside the ladder: they carry no step and, when
                                granted the power, may settle the request at any point.
                              example: false
                            step:
                              type:
                                - object
                                - 'null'
                              description: |
                                The step this validator occupies, or null for a watcher and for a request
                                with no chain. Positions are numbered from 1 in the order the steps are
                                asked.
                              required:
                                - position
                                - total
                                - name
                                - status
                                - required
                                - mandatory
                              properties:
                                position:
                                  type: integer
                                  description: "This step's place in the chain, counting from 1."
                                  example: 2
                                total:
                                  type: integer
                                  description: "How many steps the request's chain holds in all."
                                  example: 3
                                name:
                                  type: string
                                  description: |
                                    The step's name, or a generated "Step n" label when the chain left it
                                    unnamed. Frozen when the request was raised, so renaming a step later
                                    does not relabel requests already in flight.
                                  example: 'Team lead'
                                status:
                                  type: string
                                  enum:
                                    - pending
                                    - active
                                    - completed
                                    - bypassed
                                    - rejected
                                  description: |
                                    The step's state. `active` is the step holding the request; `pending` has
                                    not been reached; `bypassed` was skipped because the request was settled
                                    above it.
                                  example: active
                                required:
                                  type: integer
                                  description: 'How many approvals this step needs before it completes.'
                                  example: 2
                                mandatory:
                                  type: boolean
                                  description: |
                                    Whether this validator must approve for the step to complete. A
                                    must-approve validator holds the step even once its quorum is met.
                                  example: false
                            awaiting:
                              type: array
                              description: |
                                The validators the request is waiting on right now: those still to answer at
                                the step holding it, the caller aside. Empty when the caller is the only one
                                left to answer.
                              items:
                                type: string
                              example:
                                - 'Muller Jonas'
                  pagination:
                    type: object
                    required:
                      - page
                      - total_pages
                      - total
                      - per_page
                    properties:
                      page:
                        type: integer
                        example: 1
                      total_pages:
                        type: integer
                        example: 2
                      total:
                        type: integer
                        example: 14
                      per_page:
                        type: integer
                        example: 10
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440010
                    type: absence
                    sub_type: null
                    status: pending
                    employee_id: 550e8400-e29b-41d4-a716-446655440001
                    employee:
                      employee_id: 550e8400-e29b-41d4-a716-446655440001
                      first_name: Anna
                      last_name: Muller
                      name: 'Muller Anna'
                    requested_by: null
                    company_id: 550e8400-e29b-41d4-a716-446655440005
                    start: '2026-03-04T00:00:00+00:00'
                    end: '2026-03-06T00:00:00+00:00'
                    dates:
                      - '2026-03-04'
                      - '2026-03-05'
                      - '2026-03-06'
                    requested_time:
                      '2026-03-04': 28800
                    requested_seconds: 86400
                    next_availability:
                      if_approved:
                        absent_from: '2026-03-04'
                        next_available_date: '2026-03-09'
                        next_available_at: null
                        available_now: true
                        in_past: false
                        extends_current_absence: false
                        message: 'Off from 2026-03-04, available on 2026-03-09'
                      current:
                        next_available_date: null
                        message: null
                    comment: 'Family trip'
                    created: '2026-03-01T09:12:00+00:00'
                    modified: '2026-03-01T09:12:00+00:00'
                    validators:
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440020
                        name: 'Lemaire Farid'
                        status: pending
                        comment: null
                        step_position: 1
                        watcher: false
                        mandatory: false
                    can_decide_now: true
                    watcher: false
                    step:
                      position: 1
                      total: 2
                      name: 'Team lead'
                      status: active
                      required: 1
                      mandatory: false
                    awaiting: {}
                pagination:
                  page: 1
                  total_pages: 2
                  total: 14
                  per_page: 10
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/v2/{pbx}/employee/{employee}/pending-requests/home-office':
    get:
      tags:
        - TempusValidators
      summary: 'List the home office requests waiting on you to decide (user)'
      operationId: tempusV2ListPendingHomeOfficeRequests
      security:
        -
          bearerAuth: {}
      servers:
        -
          url: 'https://cockpit.voxbi.com/tempus/api'
          description: 'Tempus production API server'
        -
          url: 'https://staging-cockpit.voxbi.com/tempus/api'
          description: 'Tempus staging API server'
        -
          url: 'https://dev-cockpit.voxbi.com/tempus/api'
          description: 'Tempus dev API server'
      description: |
        The home office requests this employee is asked to decide, newest first.

        One entry per day-row: a home office request for a week is stored as a row per day,
        each decided on its own, and each carrying its own `id` and place in the chain. Read
        `dates` rather than `start`/`end`. Requests to take back already approved days are
        included, marked `sub_type: removal`.

        Read off the approval rows addressed to them, so approval chains are honoured
        exactly as the decision endpoints honour them: which step holds the request,
        watchers, self-approval grants, and restarts. Requests at a step below theirs are
        included with `can_decide_now: false`, so a validator further up a chain sees what
        is coming rather than having it appear from nowhere.

        Your own employee record only: another employee's id returns 403, since a queue is
        built from rows addressed to one person.

        One endpoint per request type, matching how the work is looked at: a screen showing
        one type pages that type, instead of over-fetching a mixed feed and filtering it.
        The sibling queues are `pending-requests/absences`, `pending-requests/home-office`
        and `pending-requests/time-point-corrections`; `GET /v2/{pbx}/employee/{employee}/validator`
        reports how many are waiting in each.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 'Page number to return.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 10
          description: 'Number of entries per page.'
          example: 10
        -
          name: 'filter[requester_id]'
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: |
            Narrow the queue to one person who raised requests. Named `requester_id` rather than
            `employee_id` because the employee in the path is the validator: these routes have two
            employees in play. A requester you hold no rows on yields an empty page rather than a
            403, since nothing was hidden from you.
          example: 550e8400-e29b-41d4-a716-446655440002
      responses:
        200:
          description: 'OK. Paginated home office day-rows waiting on this employee.'
          content:
            application/json:
              schema:
                type: object
                description: |
                  A page of requests waiting on one validator, one entry per request.

                  Each entry is the v2 transaction payload plus where the caller stands in that
                  request's approval chain. The envelope is hand-rolled (`data` plus `pagination`), not
                  Laravel's paginator shape. Entries are newest first.
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      allOf:
                        -
                          type: object
                          description: |
                            A request stored as a Tempus transaction: absence, illness, special leave, legal
                            holiday, home office, and removals of any of them.

                            v2 of the payload. What changed from v1 and why:

                            - **People are employees, never extensions.** v1 carried `ext_id`, a telephony
                              extension id, on a Tempus record. It was the wrong identifier for this domain (an
                              employee need not have an extension, and the field silently fell back to the
                              employee id when they did not, so it meant two different things) and it cost two
                              queries per row to produce. Everyone here is identified by `employee_id`.
                            - **One identifier per thing.** v1 repeated one value as `employee_id`,
                              `requester_id` and `creator_id`, and the request id as both `id` and
                              `absence_request_id`. Also gone: `mxvp_user_id`, which was the pbx id under a name
                              from another system, and `holiday_id`, which was always null.
                            - **Stored values, not translated ones.** v1 renamed `absence` to `legal` and
                              `approved` to `accepted` on the way out, so a client could not match what it read
                              against what it sent, nor against the request type names the approval chain uses.
                          required:
                            - id
                            - type
                            - status
                            - employee_id
                            - dates
                            - requested_time
                            - requested_seconds
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: |
                                The request id, which the decision endpoints take. For home office this is one
                                day-row: a request covering a week is stored as a row per day, each decided on
                                its own.
                              example: 550e8400-e29b-41d4-a716-446655440010
                            type:
                              type: string
                              enum:
                                - absence
                                - illness
                                - special
                                - legal_holiday
                                - home_office
                              description: 'The stored request type, not a renamed one.'
                              example: absence
                            sub_type:
                              type:
                                - string
                                - 'null'
                              description: |
                                `removal` when the request asks to take back days that were already approved,
                                otherwise null.
                              example: null
                            status:
                              type: string
                              enum:
                                - pending
                                - approved
                                - rejected
                                - cancelled
                                - pending_removal
                              description: 'The stored status.'
                              example: pending
                            employee_id:
                              type: string
                              format: uuid
                              description: 'The employee the request is for, whose balance and calendar it moves.'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            employee:
                              type:
                                - object
                                - 'null'
                              description: |
                                The same employee, by name, when the relation was loaded. Present on the validator
                                queues, absent where the endpoint does not load it.
                              properties:
                                employee_id:
                                  type: string
                                  format: uuid
                                first_name:
                                  type:
                                    - string
                                    - 'null'
                                last_name:
                                  type:
                                    - string
                                    - 'null'
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Muller Anna'
                            requested_by:
                              type:
                                - object
                                - 'null'
                              description: |
                                Who raised the request, when that is somebody other than the employee it is for
                                (raised on their behalf). Null for the ordinary case of raising your own, so a
                                client can show provenance only when there is any.
                              properties:
                                employee_id:
                                  type: string
                                  format: uuid
                                first_name:
                                  type:
                                    - string
                                    - 'null'
                                last_name:
                                  type:
                                    - string
                                    - 'null'
                                name:
                                  type:
                                    - string
                                    - 'null'
                            company_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                            start:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2026-03-04T00:00:00+00:00'
                            end:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              example: '2026-03-06T00:00:00+00:00'
                            dates:
                              type: array
                              description: |
                                The days actually asked for, which is what to read rather than the range: a
                                request can skip days.
                              items:
                                type: string
                                format: date
                              example:
                                - '2026-03-04'
                                - '2026-03-05'
                            requested_time:
                              type: object
                              description: 'Seconds asked for per day, keyed by date.'
                              additionalProperties:
                                type: integer
                              example:
                                '2026-03-04': 28800
                                '2026-03-05': 28800
                            requested_seconds:
                              type: integer
                              description: 'The sum of `requested_time`, for convenience.'
                              example: 57600
                            next_availability:
                              type: object
                              description: |
                                When an employee is next at work **if the request carrying this object goes through**,
                                next to what the general next-availability answer says today. The validator's view of a
                                request: no second call, and no cache between the queue and the date.

                                It is deliberately not the same question as `GET /user/{employee_id}/next-availability`:

                                - **Anchored at the request, not at today**, so it reports the day *this* booking frees
                                  rather than the next free day counting from now.
                                - **Counts what has been decided plus this one request.** The base is what has been
                                  signed off (accepted, plus an accepted absence somebody has asked to cancel — still
                                  time off until that cancellation is approved). Other queued requests are left out:
                                  they may be refused, and a date that moves because of a request this validator has not
                                  seen is not one they can act on. (`current` does count every pending row — that
                                  difference is intentional.)
                                - **A removal reads as a reduction**, so its answer moves *earlier*, often into the past
                                  (`in_past`), which is the signal that the employee is already back.

                                Absence, illness, special leave and legal holiday only. Home office never carries it: a
                                home office day is governed by a weekly limit, not time off that moves an availability
                                date. Neither does a request that can no longer move a date — `rejected`, `canceled` and
                                `removed`.

                                **Where it appears:** the absence lists (`/absences`, `/user/{employee_id}/absences`), the
                                absence-request reads and writes (`/absence-requests`, `/user/{employee_id}/absence-requests`
                                and its `POST`/`PUT`), `POST /user/{employee_id}/absence-removal-requests`, and both
                                validator queues (`/validator/pending-requests` — on each `absence_requests[]` /
                                `absence_removals[]` entry — and v2 `pending-requests/absences`). It is **not** on the
                                cancel responses (`POST .../absence-requests/{id}/cancel`), which report the outcome of an
                                employee's own action rather than something a validator is weighing up.

                                On the resource-backed payloads the key is **omitted** when there is nothing to say; on
                                the v1 validator queue, whose entries are built by hand, it is always present and `null`
                                in that case. Both mean the same thing.
                              required:
                                - if_approved
                                - current
                              properties:
                                if_approved:
                                  type: object
                                  description: 'Availability as it would stand with this request applied.'
                                  required:
                                    - absent_from
                                    - next_available_date
                                    - next_available_at
                                    - available_now
                                    - in_past
                                    - extends_current_absence
                                    - message
                                  properties:
                                    absent_from:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        First day, today or later, that this request itself takes off. Null when it takes
                                        nothing off in the future: a removal request, or days that have all been and gone.
                                      example: '2026-08-13'
                                    next_available_date:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        The day the employee is back at work under this scenario. Null only when no
                                        working day was found within the search horizon — an employee with no work shift,
                                        or one whose contract has ended.
                                      example: '2026-08-17'
                                    next_available_at:
                                      type:
                                        - string
                                        - 'null'
                                      description: |
                                        Exact moment they are back (`YYYY-MM-DD HH:MM:SS`) when a half day pins one down;
                                        null when only the date is meaningful.
                                      example: null
                                    available_now:
                                      type: boolean
                                      description: |
                                        Whether the employee is at work right now under this scenario. True together with
                                        a future `absent_from` is the ordinary case for a request that starts later.
                                      example: true
                                    in_past:
                                      type: boolean
                                      description: |
                                        True when `next_available_date` is already behind us, i.e. approving this would
                                        not keep anybody away from now on. Render it as "already available" rather than as
                                        a return date.
                                      example: false
                                    extends_current_absence:
                                      type: boolean
                                      description: |
                                        True when this request starts on the very day the employee would otherwise have
                                        come back, so it lengthens the absence already in place rather than opening a
                                        separate one. False for a request with working days in between — show
                                        `absent_from` as well as the return date in that case, or the return date reads as
                                        a contradiction of `available_now`.
                                      example: false
                                    message:
                                      type:
                                        - string
                                        - 'null'
                                      description: |
                                        Ready-to-display line, already covering the three cases: `Available on
                                        2026-08-17`, `Off from 2026-08-13, available on 2026-08-17`, or `Already available
                                        (was back on 2026-08-03)`. Show it as returned.
                                      example: 'Off from 2026-08-13, available on 2026-08-17'
                                current:
                                  type: object
                                  description: |
                                    Today's general answer, unchanged — the same figure
                                    `GET /user/{employee_id}/next-availability` returns, so the two screens never disagree.
                                  required:
                                    - next_available_date
                                    - message
                                  properties:
                                    next_available_date:
                                      type:
                                        - string
                                        - 'null'
                                      format: date
                                      description: |
                                        Next day the employee is available, counting from now. Null when they are
                                        available right now.
                                      example: '2026-08-12'
                                    message:
                                      type:
                                        - string
                                        - 'null'
                                      description: 'Ready-to-display line, or null while the employee is available.'
                                      example: 'Back on 2026-08-12'
                              example:
                                if_approved:
                                  absent_from: '2026-08-13'
                                  next_available_date: '2026-08-17'
                                  next_available_at: null
                                  available_now: true
                                  in_past: false
                                  extends_current_absence: false
                                  message: 'Off from 2026-08-13, available on 2026-08-17'
                                current:
                                  next_available_date: '2026-08-12'
                                  message: 'Back on 2026-08-12'
                            comment:
                              type:
                                - string
                                - 'null'
                              description: "The requester's note."
                              example: 'Family trip'
                            created:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            modified:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            validators:
                              type: array
                              description: |
                                Everyone this request asks, with their answer so far and where they sit, when the
                                approvals relation was loaded. Rows superseded by a restarted chain are left out:
                                they record what a previous round asked and are not people still to answer.
                              items:
                                type: object
                                properties:
                                  employee_id:
                                    type:
                                      - string
                                      - 'null'
                                    format: uuid
                                  name:
                                    type: string
                                    description: |
                                      The name frozen on the row when it was written, so a validator who has since
                                      been deleted still reads correctly.
                                    example: 'Lemaire Farid'
                                  status:
                                    type: string
                                    enum:
                                      - pending
                                      - accepted
                                      - rejected
                                  comment:
                                    type:
                                      - string
                                      - 'null'
                                  step_position:
                                    type:
                                      - integer
                                      - 'null'
                                    description: |
                                      Their rung in the chain, or null for a watcher, who sits outside the ladder.
                                    example: 1
                                  watcher:
                                    type: boolean
                                  mandatory:
                                    type: boolean
                                    description: |
                                      Whether their approval is required for the step to complete, whatever its
                                      quorum.
                        -
                          type: object
                          description: |
                            Where a queued request sits in its approval chain, from the point of view of the
                            validator who asked for the queue.

                            A request routes through a chain of steps, and only the step currently holding it
                            may decide. A validator therefore sees requests in two states: theirs to act on
                            now, and theirs to expect. Both are listed, so a validator on a later step is not
                            surprised by a request appearing from nowhere once the step below clears.

                            Requests raised before approval chains existed carry no step: `step` is null and
                            `can_decide_now` is true, because there is no ladder to wait on.
                          required:
                            - can_decide_now
                            - watcher
                            - step
                            - awaiting
                          properties:
                            can_decide_now:
                              type: boolean
                              description: |
                                Whether this validator may record a decision on the request right now.
                                False while the request is at a step below theirs: the decision endpoints
                                answer 409 in that case, and a client should not offer the action.
                              example: true
                            watcher:
                              type: boolean
                              description: |
                                Whether this validator holds the request as a watcher rather than as a step
                                validator. Watchers sit outside the ladder: they carry no step and, when
                                granted the power, may settle the request at any point.
                              example: false
                            step:
                              type:
                                - object
                                - 'null'
                              description: |
                                The step this validator occupies, or null for a watcher and for a request
                                with no chain. Positions are numbered from 1 in the order the steps are
                                asked.
                              required:
                                - position
                                - total
                                - name
                                - status
                                - required
                                - mandatory
                              properties:
                                position:
                                  type: integer
                                  description: "This step's place in the chain, counting from 1."
                                  example: 2
                                total:
                                  type: integer
                                  description: "How many steps the request's chain holds in all."
                                  example: 3
                                name:
                                  type: string
                                  description: |
                                    The step's name, or a generated "Step n" label when the chain left it
                                    unnamed. Frozen when the request was raised, so renaming a step later
                                    does not relabel requests already in flight.
                                  example: 'Team lead'
                                status:
                                  type: string
                                  enum:
                                    - pending
                                    - active
                                    - completed
                                    - bypassed
                                    - rejected
                                  description: |
                                    The step's state. `active` is the step holding the request; `pending` has
                                    not been reached; `bypassed` was skipped because the request was settled
                                    above it.
                                  example: active
                                required:
                                  type: integer
                                  description: 'How many approvals this step needs before it completes.'
                                  example: 2
                                mandatory:
                                  type: boolean
                                  description: |
                                    Whether this validator must approve for the step to complete. A
                                    must-approve validator holds the step even once its quorum is met.
                                  example: false
                            awaiting:
                              type: array
                              description: |
                                The validators the request is waiting on right now: those still to answer at
                                the step holding it, the caller aside. Empty when the caller is the only one
                                left to answer.
                              items:
                                type: string
                              example:
                                - 'Muller Jonas'
                  pagination:
                    type: object
                    required:
                      - page
                      - total_pages
                      - total
                      - per_page
                    properties:
                      page:
                        type: integer
                        example: 1
                      total_pages:
                        type: integer
                        example: 2
                      total:
                        type: integer
                        example: 14
                      per_page:
                        type: integer
                        example: 10
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440010
                    type: home_office
                    sub_type: null
                    status: pending
                    employee_id: 550e8400-e29b-41d4-a716-446655440001
                    employee:
                      employee_id: 550e8400-e29b-41d4-a716-446655440001
                      first_name: Anna
                      last_name: Muller
                      name: 'Muller Anna'
                    requested_by: null
                    company_id: 550e8400-e29b-41d4-a716-446655440005
                    start: '2026-03-04T00:00:00+00:00'
                    end: '2026-03-04T00:00:00+00:00'
                    dates:
                      - '2026-03-04'
                    requested_time:
                      '2026-03-04': 28800
                    requested_seconds: 28800
                    comment: null
                    created: '2026-03-01T09:12:00+00:00'
                    modified: '2026-03-01T09:12:00+00:00'
                    validators:
                      -
                        employee_id: 550e8400-e29b-41d4-a716-446655440020
                        name: 'Lemaire Farid'
                        status: pending
                        comment: null
                        step_position: 1
                        watcher: false
                        mandatory: false
                    can_decide_now: true
                    watcher: false
                    step:
                      position: 1
                      total: 2
                      name: 'Team lead'
                      status: active
                      required: 1
                      mandatory: false
                    awaiting: {}
                pagination:
                  page: 1
                  total_pages: 2
                  total: 14
                  per_page: 10
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/v2/{pbx}/employee/{employee}/pending-requests/time-point-corrections':
    get:
      tags:
        - TempusValidators
      summary: 'List the time point corrections waiting on you to decide (user)'
      operationId: tempusV2ListPendingTimePointCorrections
      security:
        -
          bearerAuth: {}
      servers:
        -
          url: 'https://cockpit.voxbi.com/tempus/api'
          description: 'Tempus production API server'
        -
          url: 'https://staging-cockpit.voxbi.com/tempus/api'
          description: 'Tempus staging API server'
        -
          url: 'https://dev-cockpit.voxbi.com/tempus/api'
          description: 'Tempus dev API server'
      description: |
        The time point correction requests this employee is asked to decide: changes to a
        recorded clock event, raised by the employee whose sheet it is.

        Read off the approval rows addressed to them, so approval chains are honoured
        exactly as the decision endpoints honour them. A correction at a step below theirs is
        included with `can_decide_now: false`.

        Your own employee record only: another employee's id returns 403.

        The payload is the v2 correction shape: people are identified by `employee_id`
        rather than v1's `requested_ext_id` (a telephony extension is not how a Tempus
        employee is identified), and the timestamps are ISO 8601 rather than several
        pre-formatted renderings of the same instant.

        Open one with
        `GET /tempus/api/v1/{pbx_id}/validator/pending-corrections/{correction_id}/details`,
        which returns the day's other time points for context and is unchanged.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 'Page number to return.'
          example: 1
        -
          name: per_page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 10
          description: 'Number of entries per page.'
          example: 10
        -
          name: 'filter[requester_id]'
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: |
            Narrow the queue to one person who raised requests. Named `requester_id` rather than
            `employee_id` because the employee in the path is the validator: these routes have two
            employees in play. A requester you hold no rows on yields an empty page rather than a
            403, since nothing was hidden from you.
          example: 550e8400-e29b-41d4-a716-446655440002
      responses:
        200:
          description: 'OK. Paginated corrections waiting on this employee.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      allOf:
                        -
                          type: object
                          description: |
                            A time point correction: a request to change a recorded clock event.

                            v2 of the payload, on the same principles as the v2 transaction. `requested_ext_id`
                            becomes `employee_id` (a telephony extension is not how a Tempus employee is
                            identified, and resolving it cost two queries per row), and the timestamps are ISO 8601
                            rather than several pre-formatted variants of the same instant: v1 returned `date`,
                            `new_datetime`, `old_datetime`, `new_time` and `old_time`, which is one moment rendered
                            five ways and leaves a client unable to reformat it.

                            A correction may have no "old" side, for instance when it asks to add a clock event
                            that was never recorded. Then `old_status`, `old_sub_status` and `old_time` are null.
                          required:
                            - id
                            - status
                            - employee_id
                            - old_status
                            - new_status
                          properties:
                            id:
                              type: string
                              format: uuid
                              example: 550e8400-e29b-41d4-a716-446655440040
                            status:
                              type: string
                              enum:
                                - pending
                                - approved
                                - rejected
                                - cancelled
                              example: pending
                            employee_id:
                              type: string
                              format: uuid
                              description: 'The employee whose attendance sheet this corrects.'
                              example: 550e8400-e29b-41d4-a716-446655440001
                            employee:
                              type:
                                - object
                                - 'null'
                              description: 'The same employee, by name, when the relation was loaded.'
                              properties:
                                employee_id:
                                  type: string
                                  format: uuid
                                first_name:
                                  type:
                                    - string
                                    - 'null'
                                last_name:
                                  type:
                                    - string
                                    - 'null'
                                name:
                                  type:
                                    - string
                                    - 'null'
                                  example: 'Muller Anna'
                            timepoint_id:
                              type:
                                - string
                                - 'null'
                              format: uuid
                              description: |
                                The clock event being changed, or null when the correction asks to add one that was
                                never recorded.
                            old_status:
                              type:
                                - object
                                - 'null'
                              description: 'The status the clock event carries now.'
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                  example: Working
                                style:
                                  type: object
                                  description: |
                                    How a status is presented. Kept as one nested object rather than flattened into
                                    `font_color` / `background_color` / `icon` siblings, so a client can pass it around
                                    without unpacking it.
                                  properties:
                                    font_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#ffffff'
                                    background_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#2f6f4f'
                                    icon:
                                      type:
                                        - string
                                        - 'null'
                                      example: 'la la-clock'
                            new_status:
                              type:
                                - object
                                - 'null'
                              description: 'The status the correction asks for.'
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                  example: Break
                                style:
                                  type: object
                                  description: |
                                    How a status is presented. Kept as one nested object rather than flattened into
                                    `font_color` / `background_color` / `icon` siblings, so a client can pass it around
                                    without unpacking it.
                                  properties:
                                    font_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#ffffff'
                                    background_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#2f6f4f'
                                    icon:
                                      type:
                                        - string
                                        - 'null'
                                      example: 'la la-clock'
                            old_sub_status:
                              type:
                                - object
                                - 'null'
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                style:
                                  type: object
                                  description: |
                                    How a status is presented. Kept as one nested object rather than flattened into
                                    `font_color` / `background_color` / `icon` siblings, so a client can pass it around
                                    without unpacking it.
                                  properties:
                                    font_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#ffffff'
                                    background_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#2f6f4f'
                                    icon:
                                      type:
                                        - string
                                        - 'null'
                                      example: 'la la-clock'
                            new_sub_status:
                              type:
                                - object
                                - 'null'
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                style:
                                  type: object
                                  description: |
                                    How a status is presented. Kept as one nested object rather than flattened into
                                    `font_color` / `background_color` / `icon` siblings, so a client can pass it around
                                    without unpacking it.
                                  properties:
                                    font_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#ffffff'
                                    background_color:
                                      type:
                                        - string
                                        - 'null'
                                      example: '#2f6f4f'
                                    icon:
                                      type:
                                        - string
                                        - 'null'
                                      example: 'la la-clock'
                            old_location:
                              type:
                                - object
                                - 'null'
                              description: |
                                The location the time point was pointed at when the correction was raised.
                                Null when it had none.
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                latitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: double
                                longitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: double
                                geofence_radius_m:
                                  type:
                                    - integer
                                    - 'null'
                            new_location:
                              type:
                                - object
                                - 'null'
                              description: |
                                The location the correction asks the time point to be recorded at. Null
                                when the correction does not touch the location, which is NOT the same as
                                asking for it to be cleared: acceptance leaves the current location as is.
                              properties:
                                id:
                                  type: string
                                  format: uuid
                                name:
                                  type: string
                                latitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: double
                                longitude:
                                  type:
                                    - number
                                    - 'null'
                                  format: double
                                geofence_radius_m:
                                  type:
                                    - integer
                                    - 'null'
                            old_time:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              description: 'When the clock event is recorded now, null when there is no old side.'
                              example: '2026-03-04T09:03:00+00:00'
                            new_time:
                              type:
                                - string
                                - 'null'
                              format: date-time
                              description: 'When the correction asks it to be.'
                              example: '2026-03-04T09:00:00+00:00'
                            correction_comment:
                              type:
                                - string
                                - 'null'
                              description: 'Why the requester says the change is needed.'
                              example: 'Badge reader was down'
                            new_comment:
                              type:
                                - string
                                - 'null'
                              description: 'The comment the corrected clock event should carry.'
                            created:
                              type:
                                - string
                                - 'null'
                              format: date-time
                        -
                          type: object
                          description: |
                            Where a queued request sits in its approval chain, from the point of view of the
                            validator who asked for the queue.

                            A request routes through a chain of steps, and only the step currently holding it
                            may decide. A validator therefore sees requests in two states: theirs to act on
                            now, and theirs to expect. Both are listed, so a validator on a later step is not
                            surprised by a request appearing from nowhere once the step below clears.

                            Requests raised before approval chains existed carry no step: `step` is null and
                            `can_decide_now` is true, because there is no ladder to wait on.
                          required:
                            - can_decide_now
                            - watcher
                            - step
                            - awaiting
                          properties:
                            can_decide_now:
                              type: boolean
                              description: |
                                Whether this validator may record a decision on the request right now.
                                False while the request is at a step below theirs: the decision endpoints
                                answer 409 in that case, and a client should not offer the action.
                              example: true
                            watcher:
                              type: boolean
                              description: |
                                Whether this validator holds the request as a watcher rather than as a step
                                validator. Watchers sit outside the ladder: they carry no step and, when
                                granted the power, may settle the request at any point.
                              example: false
                            step:
                              type:
                                - object
                                - 'null'
                              description: |
                                The step this validator occupies, or null for a watcher and for a request
                                with no chain. Positions are numbered from 1 in the order the steps are
                                asked.
                              required:
                                - position
                                - total
                                - name
                                - status
                                - required
                                - mandatory
                              properties:
                                position:
                                  type: integer
                                  description: "This step's place in the chain, counting from 1."
                                  example: 2
                                total:
                                  type: integer
                                  description: "How many steps the request's chain holds in all."
                                  example: 3
                                name:
                                  type: string
                                  description: |
                                    The step's name, or a generated "Step n" label when the chain left it
                                    unnamed. Frozen when the request was raised, so renaming a step later
                                    does not relabel requests already in flight.
                                  example: 'Team lead'
                                status:
                                  type: string
                                  enum:
                                    - pending
                                    - active
                                    - completed
                                    - bypassed
                                    - rejected
                                  description: |
                                    The step's state. `active` is the step holding the request; `pending` has
                                    not been reached; `bypassed` was skipped because the request was settled
                                    above it.
                                  example: active
                                required:
                                  type: integer
                                  description: 'How many approvals this step needs before it completes.'
                                  example: 2
                                mandatory:
                                  type: boolean
                                  description: |
                                    Whether this validator must approve for the step to complete. A
                                    must-approve validator holds the step even once its quorum is met.
                                  example: false
                            awaiting:
                              type: array
                              description: |
                                The validators the request is waiting on right now: those still to answer at
                                the step holding it, the caller aside. Empty when the caller is the only one
                                left to answer.
                              items:
                                type: string
                              example:
                                - 'Muller Jonas'
                  pagination:
                    type: object
                    required:
                      - page
                      - total_pages
                      - total
                      - per_page
                    properties:
                      page:
                        type: integer
                        example: 1
                      total_pages:
                        type: integer
                        example: 4
                      total:
                        type: integer
                        example: 38
                      per_page:
                        type: integer
                        example: 10
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/v2/{pbx}/employee/{employee}/overtime/conversion':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api'
        description: 'Tempus production API server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api'
        description: 'Tempus staging API server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api'
        description: 'Tempus dev API server'
    get:
      tags:
        - TempusOvertime
      summary: 'Preview your overtime-to-holidays conversion (user)'
      operationId: tempusV2ShowOvertimeConversion
      security:
        -
          bearerAuth: {}
      description: |
        Whether the caller can convert overtime (compensatory) balance into holiday
        days right now, and how many whole days the balance funds.

        The balance is the closing balance the last locked overtime period carried
        forward, less anything already converted in the current period. A conversion is
        possible while an overtime period is ongoing for the employee's current contract
        company and the remaining balance covers at least one whole working day, and may
        be repeated until that balance is used up.

        When `can_convert` is false, `reason` explains why and `max_days` is 0.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'OK. The conversion preview.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  can_convert:
                    type: boolean
                    description: 'Whether a conversion is currently possible.'
                  reason:
                    type:
                      - string
                      - 'null'
                    description: 'Why a conversion is not possible, or null when it is.'
                    example: null
                  current_balance_seconds:
                    type: integer
                    description: 'Convertible overtime balance, in seconds.'
                    example: 144000
                  seconds_per_day:
                    type: integer
                    description: "The employee's working day length, in seconds."
                    example: 28800
                  max_days:
                    type: integer
                    description: 'How many whole days the balance can fund (0 when none).'
                    example: 5
                  period:
                    type:
                      - object
                      - 'null'
                    description: 'The ongoing overtime period the conversion applies to.'
                    properties:
                      start:
                        type: string
                        format: date
                        example: '2026-08-01'
                      end:
                        type: string
                        format: date
                        example: '2026-08-31'
              example:
                can_convert: true
                reason: null
                current_balance_seconds: 144000
                seconds_per_day: 28800
                max_days: 5
                period:
                  start: '2026-08-01'
                  end: '2026-08-31'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
    post:
      tags:
        - TempusOvertime
      summary: 'Convert overtime balance into holiday days (user)'
      operationId: tempusV2CreateOvertimeConversion
      security:
        -
          bearerAuth: {}
      description: |
        Convert a whole number of days of overtime (compensatory) balance into legal
        holiday days on the ongoing overtime period. Irreversible. May be repeated
        within the period while balance remains.

        The credited holiday days land in the compensatory-balance pool, and the same
        amount is deducted from the overtime balance on the current period.

        422 when a conversion is not possible: no ongoing period, the remaining balance
        is under a full day, or the requested days exceed it.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is
            refused with 403 rather than answered from another tenant.
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: |
            UUID of the Tempus employee whose queue this is. Must be the caller's own employee
            record: a queue is built from the approval rows addressed to one person, so another
            employee's id is refused rather than quietly answered with your own.
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - days
              properties:
                days:
                  type: integer
                  minimum: 1
                  maximum: 99
                  description: 'Whole days of overtime balance to convert.'
                  example: 3
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                  description: 'Optional note stored on the conversion.'
                  example: 'Converting overtime earned in August.'
      responses:
        201:
          description: 'Created. The conversion was recorded.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  days:
                    type: integer
                    example: 3
                  amount_seconds:
                    type: integer
                    description: 'Overtime converted, in seconds.'
                    example: 86400
                  new_balance_seconds:
                    type: integer
                    description: 'Overtime balance remaining after the conversion, in seconds.'
                    example: 57600
                  message:
                    type: string
                    example: 'Balance converted successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            Forbidden. The caller is outside this PBX, or asked for an employee record that is
            not their own.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You do not have access to this PBX.'
        404:
          description: 'Not found. No such employee in this PBX.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'User not found.'
        422:
          description: |
            Unprocessable. The conversion is not allowed: no ongoing period, the
            remaining balance is under a full day, or the requested days exceed it.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Conversion amount exceeds the current compensatory balance.'
  '/{pbx_id}/user/{employee_id}/next-availability':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: 'Get the next availability date for an employee (user)'
      operationId: tempusGetUserNextAvailability
      description: |
        Searches forward from a start moment for the next time the employee is available and returns it. The response is a flat object and is not wrapped in a `data` envelope. When the employee is already available at that moment, `next_available_date` is `null` and `available_now` is `true` : there is no *future* availability to report, so a date equal to the current/`from` day is never returned for that case.
        The search is **time-aware**: a half day off only blocks the part of the day it covers. A morning absence (e.g. 08:00–12:00) that is under way returns **today** together with `next_available_at` = the moment it ends; an afternoon one reads as available *before* it starts and returns the next working day (date only) from the moment it does. `message` is a ready-to-display line for either case.
        When no available date is found within the search window (and the employee is not available now), the endpoint responds with 404 and a flat body reporting the searched range. A 404 is also returned when the employee cannot be found for the tenant.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose next availability is requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: from
          in: query
          required: false
          description: |
            Moment the availability search starts from. Defaults to **now** when omitted. A bare date evaluates from that day's 00:00; pass a date-time (`YYYY-MM-DD HH:MM:SS`) to ask "is the employee available at this moment?" — half days are honoured to the clock.
          schema:
            type: string
          example: '2026-03-01 09:00:00'
        -
          name: max_days
          in: query
          required: false
          description: 'Maximum number of days to search forward. Defaults to 90 when omitted.'
          schema:
            type: integer
            minimum: 1
            maximum: 365
            default: 90
          example: 90
      responses:
        200:
          description: 'The next available date for the employee. Flat object, not wrapped in data.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  next_available_date:
                    type: string
                    format: date
                    nullable: true
                    description: |
                      Date the employee is next available, or `null` when they are available at the moment checked (see `available_now`). Equal to the current/`from` day only when a half day off already under way ends later that same day.
                  next_available_at:
                    type: string
                    nullable: true
                    description: |
                      Exact moment the employee is back (`YYYY-MM-DD HH:MM:SS`) when the data pins one down — the end of a morning half day off already under way. `null` when availability is only known at day granularity (whole days off, and afternoon half days where the working day is over).
                  message:
                    type: string
                    nullable: true
                    description: |
                      Ready-to-display line: "Back on <date>", or "Back on <date> at <time>" when a half day off brings the employee back the same day. `null` while available.
                  available_now:
                    type: boolean
                    description: 'True when the employee is available at the moment checked.'
                  current:
                    type: object
                    description: 'State of the `from` day, so a client can explain the situation.'
                    properties:
                      date:
                        type: string
                        format: date
                      available:
                        type: boolean
                      reason:
                        type: string
                        description: '`available`, `absence`, `public_holiday`, `special_holiday` or `non_working_day`.'
                      absence:
                        type: object
                        nullable: true
                        description: 'The absence covering the moment checked; `null` when none does.'
                        properties:
                          type:
                            type: string
                          sub_type:
                            type: string
                            nullable: true
                          status:
                            type: string
                          start:
                            type: string
                            format: date
                          end:
                            type: string
                            format: date
                      absence_window:
                        type: object
                        nullable: true
                        description: |
                          The intraday window a half day off covers on this day — reported even when the employee is available (before it starts / after it ends). `null` when the day is off as a whole or not off at all.
                        properties:
                          start:
                            type: string
                          end:
                            type: string
                          part:
                            type: string
                            enum:
                              - am
                              - pm
                  employee_id:
                    type: string
                    format: uuid
                  checked_from:
                    type: string
                    format: date
                  checked_from_at:
                    type: string
                    description: 'The exact moment the search evaluated from.'
                  checked_until:
                    type: string
                    format: date
              example:
                success: true
                next_available_date: '2026-03-02'
                next_available_at: '2026-03-02 12:00:00'
                message: 'Back on 2026-03-02 at 12:00'
                available_now: false
                current:
                  date: '2026-03-02'
                  available: false
                  reason: absence
                  absence:
                    type: legal
                    sub_type: null
                    status: approved
                    start: '2026-03-02'
                    end: '2026-03-02'
                  absence_window:
                    start: '2026-03-02 08:00:00'
                    end: '2026-03-02 12:00:00'
                    part: am
                employee_id: 550e8400-e29b-41d4-a716-446655440001
                checked_from: '2026-03-02'
                checked_from_at: '2026-03-02 09:00:00'
                checked_until: '2026-05-30'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: |
            No available date was found within the search window, or the employee could not be found for the tenant. The body is a flat object reporting the searched range.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  employee_id:
                    type: string
                    format: uuid
                  checked_from:
                    type: string
                    format: date
                  checked_from_at:
                    type: string
                  checked_until:
                    type: string
                    format: date
              example:
                success: false
                message: 'No available date found within the search range.'
                employee_id: 550e8400-e29b-41d4-a716-446655440001
                checked_from: '2026-03-01'
                checked_from_at: '2026-03-01 00:00:00'
                checked_until: '2026-05-30'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/public-holidays':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: 'List public holidays for an employee (user)'
      operationId: tempusListUserPublicHolidays
      description: |
        Returns a paginated list of public holidays relevant to the employee. The countries are derived from the employee's contracts that overlap the requested date range, and holidays are returned for those countries. When no date filters are supplied the range defaults to the current calendar year. Filtering and sorting are powered by Spatie Query Builder.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose public holidays are requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Return holidays on or after this date. Defaults to the start of the current year.'
          schema:
            type: string
            format: date
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Return holidays on or before this date. Defaults to the end of the current year.'
          schema:
            type: string
            format: date
          example: '2026-12-31'
        -
          name: sort
          in: query
          required: false
          description: 'Sort field. Allowed: date. Prefix with - for descending.'
          schema:
            type: string
          example: date
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 15
          example: 15
      responses:
        200:
          description: "Paginated list of public holidays for the employee's countries."
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusPublicHoliday'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/profile':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: 'Get the Tempus profile for an employee (user)'
      operationId: tempusGetUserProfile
      description: |
        Returns the consolidated Tempus profile for a single employee, assembled from the employee's active contract and company: the company, the contract dates, basic employee contact fields, and per-feature summaries (absence, home office allowance, overtime). The caller may only view their own profile: the request is rejected with 403 when the authenticated user has no access to the tenant or the employee record is not their own, with 404 when the employee or its linked user account cannot be found, and with 422 when the employee has no active contract to build a profile from.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose profile is requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'The assembled Tempus profile for the employee.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusUserProfile'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'The employee has no active contract, so no profile can be produced.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                properties:
                  message:
                    type: string
                    example: 'Employee has no active contract.'
  '/{pbx_id}/user/{employee_id}/travel-time':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: "List an employee's travel time credits"
      operationId: tempusListUserTravelTime
      description: |
        Returns the travel time credits recorded for the employee in the given date range, newest first, plus the current allowance in `meta`. Defaults to the current month when `from` and `to` are omitted. The caller may only read their own credits: the request is rejected with 403 when the authenticated user has no access to the tenant or the employee record is not their own, and with 404 when the employee cannot be found. When travel time is not configured for the PBX the list is empty and `meta.enabled` reflects the employee's own flag.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose credits are requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: from
          in: query
          required: false
          description: 'Start of the range, `Y-m-d`. Defaults to the first day of the current month.'
          schema:
            type: string
            format: date
          example: '2026-05-01'
        -
          name: to
          in: query
          required: false
          description: 'End of the range, `Y-m-d`. Must not be earlier than `from`. Defaults to today.'
          schema:
            type: string
            format: date
          example: '2026-05-31'
      responses:
        200:
          description: "The employee's travel time credits and current allowance."
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusTravelTimeCredit'
                  meta:
                    type: object
                    required:
                      - enabled
                      - minutes_per_request
                      - max_per_day
                      - used_today
                      - remaining_today
                      - pending_today
                    properties:
                      enabled:
                        type: boolean
                        description: 'Whether travel time is enabled for this employee.'
                        example: true
                      minutes_per_request:
                        type: integer
                        format: int32
                        description: 'Payable minutes credited per request.'
                        example: 30
                      max_per_day:
                        type: integer
                        format: int32
                        description: 'How many credits are allowed per date.'
                        example: 1
                      used_today:
                        type: integer
                        format: int32
                        description: 'Credits already taken today.'
                        example: 1
                      remaining_today:
                        type: integer
                        format: int32
                        description: 'Credits still available today.'
                        example: 0
                      pending_today:
                        type: integer
                        format: int32
                        description: |
                          Requests for today filed for HR and not yet accepted. Nothing has been credited for these; they are waiting in the correction queue.
                        example: 0
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'The `from` or `to` query parameter is malformed, or `to` precedes `from`.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - errors
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                example:
                  message: 'The given data was invalid.'
                  errors:
                    to:
                      - 'The to field must be a date after or equal to from.'
    post:
      tags:
        - TempusProfile
      summary: 'Credit travel time to a day'
      operationId: tempusStoreUserTravelTime
      description: |
        Credits the employee's configured travel time allowance to a date.

        Two successful outcomes, both on the happy path:

        * `201` — the minutes were placed and paid; the body carries the time point.
        * `202` — the day had no room the system would use, so the request was filed
          as a PENDING time point correction for a validator to place by hand.
          Nothing has been credited yet and the allowance is untouched.

        **Placement.** A day's payable total is bounded by the shape of its rows: each
        row runs until the next one starts, so a block laid over payable time only
        relabels minutes already counted. Only a placement that replaces UNPAYABLE
        time, or extends past the day's outer edge, actually pays. Three are tried in
        order, and the first that fits the WHOLE allowance wins:

        * `start_of_day` — ends exactly where the day's first PAYABLE status begins.
          Unpayable rows at the start of a day (a midnight rollover row, an auto-stop
          row, an early break) are room rather than an obstacle.
        * `end_of_day` — appended after the day's last CLOSED row, then closed again
          by the employee's own last unpayable status, or the configured stop status.
        * `mid_day` — the tail of an unpayable stretch, preferring one that work
          resumes after. This is what covers a day the employee is still clocked in on.

        An empty day is anchored at the PBX's configured empty day time (06:00 by
        default) and closed by the configured stop status. Repeat requests on the same
        day chain backwards from the earlier credit, producing one contiguous block.

        **Guarantees.** A credit is exactly the configured minutes or it is not written
        (partial credits no longer exist); it never crosses another row's boundary, so
        at most one existing row is touched — its end pulled back to the credit's start,
        with the old value kept in that row's `meta_data.travel_time_trimmed`; live
        (open) rows are never touched; nothing is written into the future. After the
        write the day's payable seconds are re-measured and compared against the value
        before it — anything other than exactly the allowance is rolled back and
        returned as `202`.

        The credit is recorded as an accepted time point correction, so it appears in
        the employee's correction history and remains correctable afterwards. No
        acceptance email is sent.

        The caller may only credit their own travel time: the request is rejected with
        403 when the authenticated user has no access to the tenant or the employee
        record is not their own, and with 404 when the employee cannot be found.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee to credit.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                date:
                  type: string
                  format: date
                  description: |
                    The date to credit, `Y-m-d`. Defaults to today. Must not be in the future, and must not be older than the PBX's configured `travel_time.max_past_days` window (31 days by default).
                  example: '2026-05-11'
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                  description: |
                    Optional note stored on the credit. Defaults to a generated "Travel time requested" comment.
                  example: 'Client site visit'
      responses:
        201:
          description: 'The travel time credit was applied.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - data
                  - meta
                properties:
                  message:
                    type: string
                    example: 'Travel time has been added.'
                  data:
                    type: object
                    required:
                      - timepoint_id
                      - correction_id
                      - status_id
                      - start_time
                      - placement
                    properties:
                      timepoint_id:
                        type: string
                        format: uuid
                        description: 'UUID of the time point created for the credit.'
                        example: 550e8400-e29b-41d4-a716-446655440012
                      correction_id:
                        type: string
                        format: uuid
                        description: 'UUID of the accepted correction row behind the credit.'
                        example: 550e8400-e29b-41d4-a716-446655440013
                      placement:
                        type: string
                        enum:
                          - start_of_day
                          - end_of_day
                          - mid_day
                          - empty_day
                        description: |
                          Which placement was used, so a client can explain a timestamp that is not first thing in the morning.
                        example: start_of_day
                      status_id:
                        type: string
                        format: uuid
                        description: 'UUID of the PBX travel time status.'
                        example: 550e8400-e29b-41d4-a716-446655440011
                      start_time:
                        type: string
                        description: 'Start of the credited block, `Y-m-d H:i:s`.'
                        example: '2026-05-11 07:30:00'
                      end_time:
                        type:
                          - string
                          - 'null'
                        description: 'End of the credited block, `Y-m-d H:i:s`.'
                        example: '2026-05-11 08:00:00'
                      minutes:
                        type:
                          - integer
                          - 'null'
                        format: int32
                        description: |
                          Minutes credited. Always equal to the configured allowance — a placement that cannot pay it in full is refused rather than shortened. Null only for the pathological case of a time point written without an end.
                        example: 30
                      comment:
                        type:
                          - string
                          - 'null'
                        description: 'The comment stored on the credit.'
                        example: 'Client site visit'
                  meta:
                    type: object
                    required:
                      - used_today
                      - remaining_today
                      - pending_today
                    properties:
                      used_today:
                        type: integer
                        format: int32
                        example: 1
                      remaining_today:
                        type: integer
                        format: int32
                        example: 0
                      pending_today:
                        type: integer
                        format: int32
                        description: 'Requests for today waiting for HR. Nothing credited for these.'
                        example: 0
        202:
          description: |
            The day had no room the system would use, so the request was filed as a pending time point correction for a validator. NOTHING has been credited: there is no time point, the allowance is untouched, and `pending_today` counts the waiting request. A second request for the same date is refused with `already_pending` until this one is settled.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - code
                  - data
                  - meta
                properties:
                  message:
                    type: string
                    example: 'Please contact HR as your day has no room available for adjusting this timepoint. Your request has been sent to them for approval.'
                  code:
                    type: string
                    enum:
                      - pending_hr_review
                    example: pending_hr_review
                  data:
                    type: object
                    required:
                      - correction_id
                      - status_id
                    properties:
                      correction_id:
                        type: string
                        format: uuid
                        description: 'UUID of the pending correction a validator will settle.'
                        example: 550e8400-e29b-41d4-a716-446655440013
                      status_id:
                        type: string
                        format: uuid
                        description: 'UUID of the PBX travel time status.'
                        example: 550e8400-e29b-41d4-a716-446655440011
                      requested_time:
                        type:
                          - string
                          - 'null'
                        description: |
                          The placement the system wanted, `Y-m-d H:i:s` — thirty minutes before the day's first payable status, or the PBX's empty day anchor when that falls off the day.
                        example: '2026-05-11 06:00:00'
                      comment:
                        type:
                          - string
                          - 'null'
                        description: 'The comment the employee sent with the request.'
                        example: 'Client site visit'
                  meta:
                    type: object
                    required:
                      - used_today
                      - remaining_today
                      - pending_today
                    properties:
                      used_today:
                        type: integer
                        format: int32
                        example: 0
                      remaining_today:
                        type: integer
                        format: int32
                        example: 1
                      pending_today:
                        type: integer
                        format: int32
                        example: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: |
            Either the `date` or `comment` field failed validation (standard
            validation error body), or a travel time guard refused the request. Guard
            refusals carry a stable machine readable `code` alongside the translated
            `message`:

            | code | meaning |
            |---|---|
            | `not_allowed` | Travel time is not enabled for this employee. |
            | `employee_user_missing` | The employee is not linked to a user account. |
            | `status_not_configured` | No status is marked as travel time for the PBX. |
            | `status_ambiguous` | More than one status is marked as travel time. |
            | `stop_status_not_configured` | The day is empty and no stop status is configured. |
            | `stop_status_same_as_travel` | The stop status is misconfigured to equal the travel status. |
            | `minutes_not_configured` | The configured duration is zero or negative. |
            | `date_in_future` | The requested date is in the future. |
            | `date_locked` | The requested date is older than the allowed window. |
            | `no_contract` | The employee has no active contract on that date. |
            | `absence_day` | The date is covered by an approved absence. |
            | `limit_reached` | The per-date allowance is already used up. |
            | `already_pending` | A request for this date is already waiting for HR. |
          content:
            application/json:
              schema:
                oneOf:
                  -
                    type: object
                    title: 'Guard refusal'
                    required:
                      - message
                      - code
                    properties:
                      message:
                        type: string
                        example: 'The travel time limit for this date has already been reached.'
                      code:
                        type: string
                        example: limit_reached
                  -
                    type: object
                    title: 'Field validation error'
                    required:
                      - message
                      - errors
                    properties:
                      message:
                        type: string
                        example: 'The given data was invalid.'
                      errors:
                        type: object
                        additionalProperties:
                          type: array
                          items:
                            type: string
  '/{pbx_id}/user/{employee_id}/user-companies':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: 'List companies associated with an employee (user)'
      operationId: tempusListUserCompanies
      description: |
        Returns a paginated list of the employee's contracts, each enriched with its company details. When no active filter is supplied, the currently active contract is flagged as the main company. Filtering and sorting are powered by Spatie Query Builder. The caller may only list their own companies: the request is rejected with 403 when the authenticated user has no access to the tenant or the employee record is not their own, and with 404 when the employee cannot be found.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose companies are requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Return contracts whose start date is on or after this date.'
          schema:
            type: string
            format: date
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Return contracts whose end date is on or before this date. Must be on or after filter[from].'
          schema:
            type: string
            format: date
          example: '2026-12-31'
        -
          name: 'filter[active]'
          in: query
          required: false
          description: 'Restrict to active (true/1) or ended (false/0) contracts.'
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
              - '1'
              - '0'
          example: 'true'
        -
          name: sort
          in: query
          required: false
          description: 'Sort field. Allowed: from (contract_start), to (contract_end). Prefix with - for descending.'
          schema:
            type: string
          example: '-from'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 15
      responses:
        200:
          description: "Paginated list of the employee's companies."
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusUserCompany'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/holidays-reports':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusProfile
      summary: 'Get the holidays report for an employee (user)'
      operationId: tempusGetUserHolidaysReport
      description: |
        Returns the legal-holiday report for the employee for a given year, derived from the transaction ledger. The report includes the possible, taken, expired and remaining holiday balances, the compensatory balance and extra time, plus a per-year pool details list. The response is a flat object and is not wrapped in a `data` envelope. The request is rejected with 403 when the authenticated user does not belong to the requested tenant, and with 404 when the employee cannot be found.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose holidays report is requested.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: year
          in: query
          required: false
          description: 'Four-digit year for the report. Defaults to the current year when omitted.'
          schema:
            type: string
            pattern: '^\d{4}$'
          example: '2026'
      responses:
        200:
          description: 'The holidays report for the employee. Flat object, not wrapped in data.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  possible_holidays:
                    type: number
                    description: 'Total holiday credit plus overtime balance available.'
                  taken_holidays:
                    type: number
                    description: 'Holiday time already taken.'
                  expired_holidays:
                    type: number
                  remaining_holidays:
                    type: number
                    description: 'Remaining legal-holiday balance.'
                  pools_times_details_for_year:
                    type: array
                    items:
                      type: object
                  compensatory_balance:
                    type: number
                  extra_time:
                    type: number
              example:
                possible_holidays: 936000
                taken_holidays: 288000
                expired_holidays: 0
                remaining_holidays: 648000
                pools_times_details_for_year: {}
                compensatory_balance: 0
                extra_time: 0
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user does not belong to the requested tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/compiled-user-workshifts':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusWorkTimes
      summary: 'List compiled workshifts for an employee (user)'
      operationId: tempusListCompiledUserWorkshifts
      description: |
        Returns the paginated list of compiled (precomputed) workshift entries for a
        single Tempus employee within the given PBX tenant. Each entry summarizes the
        worked time the Tempus engine has rolled up for one calendar day, attributing
        it to the employee's effective work shift and work week.

        Results are sorted by `date` descending by default and support `from`/`to`
        date filtering. The authenticated user may only read their own compiled
        workshifts; requesting another employee's data returns 403.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the Tempus employee whose compiled workshifts are listed.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Include only entries on or after this calendar date (YYYY-MM-DD).'
          schema:
            type: string
            format: date
            example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Include only entries on or before this calendar date (YYYY-MM-DD).'
          schema:
            type: string
            format: date
            example: '2024-03-31'
        -
          name: sort
          in: query
          required: false
          description: 'Sort field. Use `date` for ascending or `-date` for descending.'
          schema:
            type: string
            enum:
              - date
              - '-date'
            example: '-date'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
            example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of records per page (1 to 100).'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            example: 15
      responses:
        200:
          description: 'Paginated collection of compiled workshift entries.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - links
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusCompiledUserWorkshift'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user may only view their own compiled workshifts.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You can only view your own compiled user workshifts.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/interactive-calendar':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusWorkTimes
      summary: 'Build the interactive calendar for an employee (user)'
      operationId: tempusBuildInteractiveCalendar
      description: |
        Builds the interactive home-office and absence calendar for a single Tempus
        employee (`ext_id`) over a from/to month-year window within the given PBX
        tenant. The window must be valid (the `to` period must be greater than or
        equal to `from`) and may not exceed 24 months.

        The authenticated user must belong to the same PBX tenant. Viewing another
        employee's calendar requires absence-validation or home-office-validation
        scope over that employee; otherwise a 403 is returned. The response is a
        JSON object whose `data` payload is assembled by the calendar builder and
        varies with the requested window.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ext_id
                - from
                - to
              properties:
                ext_id:
                  type: string
                  format: uuid
                  description: 'UUID of the target Tempus employee whose calendar is built.'
                  example: 550e8400-e29b-41d4-a716-446655440001
                from:
                  type: object
                  description: 'Start of the month-year window (inclusive).'
                  required:
                    - year
                    - month
                  properties:
                    year:
                      type: integer
                      minimum: 1970
                      maximum: 2100
                      example: 2024
                    month:
                      type: integer
                      minimum: 1
                      maximum: 12
                      example: 3
                to:
                  type: object
                  description: 'End of the month-year window (inclusive).'
                  required:
                    - year
                    - month
                  properties:
                    year:
                      type: integer
                      minimum: 1970
                      maximum: 2100
                      example: 2024
                    month:
                      type: integer
                      minimum: 1
                      maximum: 12
                      example: 6
            example:
              ext_id: 550e8400-e29b-41d4-a716-446655440001
              from:
                year: 2024
                month: 3
              to:
                year: 2024
                month: 6
      responses:
        200:
          description: 'The assembled interactive calendar for the requested window.'
          content:
            application/json:
              schema:
                type: object
                description: |
                  Interactive calendar payload assembled by the calendar builder. Not wrapped in an envelope; the `data` key below is a field of the payload, not a resource wrapper. The concrete contents depend on the requested window and the employee's schedule, absences and home office entries.
                properties:
                  ext_id:
                    type: string
                    format: uuid
                    description: 'The target employee id.'
                  month_calendars:
                    type: object
                    description: 'Object keyed by `YYYY-MM`; each value is one month grid (days plus week rows).'
                    additionalProperties:
                      type: object
                  data:
                    type: object
                    description: |
                      Aggregated calendar data: `public_holidays`, `home_office_module`, `absence_module`, `compiled_workshifts` (seconds of required work per day) and `active_company_id` (nullable).
              example:
                ext_id: 550e8400-e29b-41d4-a716-446655440002
                month_calendars:
                  2026-07:
                    key: 2026-07
                    year: 2026
                    month_index: 7
                    month_name: July
                    formatted_date: '2026-06-29 - 2026-08-02'
                    data:
                      '2026-07-14':
                        day: 14
                        day_of_week: 2
                        is_same_month: true
                        entry:
                          type: public-holiday
                          id: 550e8400-e29b-41d4-a716-446655440000
                          date: '2026-07-14'
                        entries:
                          -
                            type: public-holiday
                            id: 550e8400-e29b-41d4-a716-446655440000
                            date: '2026-07-14'
                    weeks:
                      -
                        week_of_year: 28
                        dates:
                          - '2026-07-06'
                          - '2026-07-07'
                          - '2026-07-08'
                          - '2026-07-09'
                          - '2026-07-10'
                          - '2026-07-11'
                          - '2026-07-12'
                data:
                  public_holidays:
                    550e8400-e29b-41d4-a716-446655440000:
                      id: 550e8400-e29b-41d4-a716-446655440000
                      date: '2026-07-14'
                      name: 'National Day'
                  home_office_module:
                    module_enabled: true
                    has_permission_to_validate: true
                    has_permission_to_request: true
                    calendar:
                      approved_days:
                        - '2026-07-20'
                      requested_days:
                        - '2026-07-27'
                      removed_days: {}
                      comment: ''
                    summary:
                      2026:
                        used: 5
                        allowance: 40
                        remaining: 35
                    validated_dates: {}
                  absence_module:
                    module_enabled: true
                    has_permission_to_validate: true
                    has_permission_to_request: true
                    absences: {}
                    absence_requests: {}
                    absence_removals: {}
                    summary:
                      2026:
                        possible: '25 days'
                        taken: '5 days'
                        remaining: '20 days'
                  compiled_workshifts:
                    '2026-07-01': 28800
                    '2026-07-14': 0
                  active_company_id: 550e8400-e29b-41d4-a716-446655440030
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the tenant, or lacks validation scope
            over the requested employee's calendar.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You are not authorized to view this calendar.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/user-overtime-decision/getOvertime':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusOvertime
      summary: 'Calculate overtime for an employee over a date range (user)'
      operationId: tempusGetUserOvertime
      description: |
        Calculates the accumulated overtime for a single Tempus employee within a date range and returns it split into `business` (overtime worked on regular business days) and `non_working` (overtime worked on weekends, public holidays and other non-working days). Both figures are expressed in seconds.

        The window is taken from the `start` and `end` query parameters. When neither is supplied the endpoint falls back to the employee's current overtime period. The range may not exceed the configured maximum number of months (default 3); a longer range is rejected with 422. The employee must belong to the requested PBX tenant, otherwise the request returns 404.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the Tempus employee.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: start
          in: query
          required: false
          description: |
            Start of the range (any parseable date). Must be on or before `end`. When omitted the employee's current overtime period start is used.
          schema:
            type: string
            format: date
          example: '2024-03-01'
        -
          name: end
          in: query
          required: false
          description: |
            End of the range (any parseable date). Must be on or after `start` and within the configured maximum span from `start`. When omitted the employee's current overtime period end is used.
          schema:
            type: string
            format: date
          example: '2024-03-31'
      responses:
        200:
          description: 'Calculated overtime totals in seconds.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - business
                  - non_working
                properties:
                  business:
                    type: integer
                    description: 'Overtime accumulated on regular business days, in seconds.'
                    example: 7200
                  non_working:
                    type: integer
                    description: |
                      Overtime accumulated on non-working days (weekends, public holidays), in seconds.
                    example: 1800
              example:
                business: 7200
                non_working: 1800
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/user-overtime-decision':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusOvertime
      summary: "List a specific employee's overtime decisions (user)"
      operationId: tempusListUserOvertimeDecisions
      description: |
        Returns a paginated list of overtime decisions recorded for a single Tempus employee within the PBX tenant. Each item is serialized by the `UserOvertimeDecisionResource`. When no `filter[overtime_calculation_period_id]` is supplied the list is automatically restricted to the employee's current overtime period. The caller must be authorized to view the employee's own decisions, otherwise the request is rejected with 403, and the employee must belong to the requested PBX tenant, otherwise 404 is returned.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the Tempus employee.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[overtime_calculation_period_id]'
          in: query
          required: false
          description: |
            Restrict results to a single overtime calculation period. When omitted the current period is used automatically.
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440060
        -
          name: sort
          in: query
          required: false
          description: |
            Sort order. Supports `created_at` and `overtime_calculation_period.start`, each prefixable with `-` for descending. Defaults to `-created_at`.
          schema:
            type: string
          example: '-created_at'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 2000
            default: 20
          example: 20
      responses:
        200:
          description: "Paginated list of the employee's overtime decisions."
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusUserOvertimeDecision'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: "The caller is not authorized to view this employee's overtime decisions."
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusOvertime
      summary: "Create or update an employee's overtime decision (user)"
      operationId: tempusStoreUserOvertimeDecision
      description: |
        Creates or updates the overtime decision for a single Tempus employee for an overtime calculation period. The endpoint recalculates the period's overtime, derives `to_pay` / `to_increment` from the chosen `decision` (or from an explicit `to_pay`), and persists the decision via an upsert keyed on tenant, employee and period.

        The stored row is fully derived server-side, so the response is the authoritative "after" state:

        * `decision_balance` — the balance carried into the period, taken from the
          last LOCKED period's closing balance (never from an unlocked draft).
        * `decision_overtime` — the period's accrual UP TO TODAY. Days that have not
          happened yet are not counted, so a decision taken mid-period no longer
          reports the remaining workdays as undertime.
        * `to_pay` — what is cashed out, capped at
          `decision_balance + decision_overtime` and never negative.
        * `to_increment` — `decision_overtime - to_pay`, i.e. what lands on the
          balance. Negative when the payout is drawn from the carried-in balance.
        * `decision_new_balance` — what is left afterwards.

        When `overtime_calculation_period_id` is omitted the active period is resolved from the employee's current contract; if no active contract or no active decision period can be resolved the request is rejected with 422. If a decision for the period has already been processed (locked) it can no longer be changed and the request returns 403. The employee must belong to the requested PBX tenant, otherwise 404 is returned.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the Tempus employee.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
              properties:
                decision:
                  type: string
                  enum:
                    - pay
                    - add_to_balance
                    - custom
                  description: |
                    What to do with the calculated overtime. `pay` cashes out the whole accrual, `add_to_balance` rolls all of it into the employee's overtime balance, and `custom` means the split is given explicitly through `to_pay`.
                  example: add_to_balance
                to_pay:
                  type:
                    - integer
                    - string
                  minimum: 0
                  description: |
                    How much to cash out, as a whole number of seconds (`43200`) or as `"HH:MM"` (`"12:00"`). Overrides `decision`, so an employee can be paid part of the period and bank the rest; the remainder (`decision_overtime - to_pay`) goes to the balance. An explicit `0` means "pay nothing". Rejected with 422 when it exceeds the balance carried in plus the period's accrual. When omitted, the amount follows the `decision` label.
                  example: 43200
                overtime_calculation_period_id:
                  type: string
                  format: uuid
                  description: |
                    Optional overtime calculation period the decision applies to. Must exist within the requested PBX tenant. When omitted the active period is resolved from the employee's current contract.
                  example: 550e8400-e29b-41d4-a716-446655440060
            example:
              decision: custom
              overtime_calculation_period_id: 550e8400-e29b-41d4-a716-446655440060
              to_pay: 43200
      responses:
        200:
          description: 'The created or updated overtime decision.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusUserOvertimeDecision'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The overtime decision for this period has already been processed and is locked.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: |
            Validation failed: an unknown period, a `to_pay` larger than the employee's available time, or no active contract / decision period to resolve.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'You asked to be paid 12:00 but only 07:44 is available (balance carried in plus the overtime accrued this period).'
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                example:
                  message: 'You asked to be paid 12:00 but only 07:44 is available (balance carried in plus the overtime accrued this period).'
                  errors:
                    to_pay:
                      - 'You asked to be paid 12:00 but only 07:44 is available (balance carried in plus the overtime accrued this period).'
  '/{pbx_id}/user/{employee_id}/user-overtime-decision-preference':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusOvertime
      summary: "Read the employee's overtime decision preference (user)"
      operationId: tempusShowUserOvertimeDecisionPreference
      description: |
        Returns the employee's standing overtime decision preference, the same row HR edits under "Decision Preferences" on the employee record, plus the options, bounds and defaults needed to render the form.

        `data` is null when the employee has never saved a preference; in that case `meta.configured` is false and the company level rule applies. Read the starting values for the form from `meta.defaults`.

        Self service only. The request is rejected with 403 when the authenticated user has no access to the tenant or the employee record is not their own, and with 404 when the employee cannot be found.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: "UUID of the employee. Must be the authenticated user's own employee record."
          schema:
            type: string
            format: uuid
          example: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
      responses:
        200:
          description: 'The current preference, or null when none has been saved.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - meta
                properties:
                  data:
                    oneOf:
                      -
                        $ref: '#/components/schemas/TempusOvertimeDecisionPreference'
                      -
                        type: 'null'
                  meta:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreferenceMeta'
              examples:
                configured:
                  summary: 'A preference has been saved'
                  value:
                    data:
                      id: 9b1f0c62-4d0a-4e2f-9f43-6f4a5c8d1e70
                      scope: employee
                      employee_id: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
                      auto_decision_policy: force_auto_decision
                      auto_decision_policy_label: 'Force auto-decision (override manual)'
                      policy_reason: 'Prefers time off over payout'
                      preferred_decision: increment_up_to
                      preferred_decision_label: 'Increment balance up to X hours'
                      max_seconds: 28800
                      max_hours: 8
                      rest_policy: add_to_balance
                      rest_policy_label: 'Add to balance'
                      is_active: true
                      created_at: '2026-08-06 09:14:22'
                      updated_at: '2026-08-06 10:02:51'
                    meta:
                      configured: true
                      options:
                        auto_decision_policy:
                          skip_if_manual_decision: 'Skip if manual decision exists'
                          force_auto_decision: 'Force auto-decision (override manual)'
                          force_zero_overtime: 'Force zero overtime (not eligible)'
                        preferred_decision:
                          pay_up_to: 'Pay up to X hours (specify max time)'
                          increment_up_to: 'Increment balance up to X hours (specify max time)'
                        rest_policy:
                          add_to_balance: 'Add to balance'
                          drop: 'Drop (ignore remaining hours)'
                      limits:
                        min_seconds: 3600
                        max_seconds: 115200
                        min_hours: 1
                        max_hours: 32
                      defaults:
                        auto_decision_policy: skip_if_manual_decision
                        preferred_decision: pay_up_to
                        rest_policy: add_to_balance
                        max_seconds: 3600
                        max_hours: 1
                        is_active: true
                notConfigured:
                  summary: 'No preference saved yet'
                  value:
                    data: null
                    meta:
                      configured: false
                      options:
                        auto_decision_policy:
                          skip_if_manual_decision: 'Skip if manual decision exists'
                          force_auto_decision: 'Force auto-decision (override manual)'
                          force_zero_overtime: 'Force zero overtime (not eligible)'
                        preferred_decision:
                          pay_up_to: 'Pay up to X hours (specify max time)'
                          increment_up_to: 'Increment balance up to X hours (specify max time)'
                        rest_policy:
                          add_to_balance: 'Add to balance'
                          drop: 'Drop (ignore remaining hours)'
                      limits:
                        min_seconds: 3600
                        max_seconds: 115200
                        min_hours: 1
                        max_hours: 32
                      defaults:
                        auto_decision_policy: skip_if_manual_decision
                        preferred_decision: pay_up_to
                        rest_policy: add_to_balance
                        max_seconds: 3600
                        max_hours: 1
                        is_active: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - TempusOvertime
      summary: "Save the employee's overtime decision preference (user)"
      operationId: tempusUpdateUserOvertimeDecisionPreference
      description: |
        Creates or replaces the employee's overtime decision preference. There is at
        most one employee level row, so this is an upsert: 201 the first time, 200
        on every later call. It writes the same row HR edits under "Decision
        Preferences", so a change made here is visible to HR immediately.

        This is a full replace, not a patch. Fields left out are reset: `policy_reason`
        becomes null and `is_active` becomes true.

        **Which fields are required depends on `auto_decision_policy`:**

        | `auto_decision_policy` | `preferred_decision` | cap | `rest_policy` |
        |---|---|---|---|
        | `skip_if_manual_decision` | required | required | required |
        | `force_auto_decision` | required | required | required |
        | `force_zero_overtime` | ignored, stored as null | ignored, stored as null | ignored, stored as null |

        The cap may be sent as `max_seconds` or as `max_hours`; `max_seconds` wins
        when both are present. `max_hours` is multiplied by 3600 and rounded to the
        nearest second. One of the two is required unless the policy is
        `force_zero_overtime`.

        Self service only. The request is rejected with 403 when the authenticated
        user has no access to the tenant or the employee record is not their own,
        and with 404 when the employee cannot be found.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: "UUID of the employee. Must be the authenticated user's own employee record."
          schema:
            type: string
            format: uuid
          example: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - auto_decision_policy
              properties:
                auto_decision_policy:
                  type: string
                  enum:
                    - skip_if_manual_decision
                    - force_auto_decision
                    - force_zero_overtime
                  description: 'How the automatic overtime decision behaves.'
                  example: force_auto_decision
                policy_reason:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free text note. Reset to null when omitted.'
                  example: 'Prefers time off over payout'
                preferred_decision:
                  type:
                    - string
                    - 'null'
                  enum:
                    - pay_up_to
                    - increment_up_to
                    - null
                  description: |
                    What to do with the overtime up to the cap. Required unless `auto_decision_policy` is `force_zero_overtime`, in which case it is ignored and stored as null.
                  example: increment_up_to
                max_hours:
                  type:
                    - number
                    - 'null'
                  format: float
                  minimum: 1
                  maximum: 32
                  description: |
                    The cap in hours. Converted to seconds on save. Send this or `max_seconds`, not necessarily both.
                  example: 8
                max_seconds:
                  type:
                    - integer
                    - 'null'
                  format: int32
                  minimum: 3600
                  maximum: 115200
                  description: 'The cap in seconds. Takes precedence over `max_hours` when both are sent.'
                  example: 28800
                rest_policy:
                  type:
                    - string
                    - 'null'
                  enum:
                    - add_to_balance
                    - drop
                    - null
                  description: |
                    What happens to the overtime above the cap. Required unless `auto_decision_policy` is `force_zero_overtime`, in which case it is ignored and stored as null.
                  example: add_to_balance
                is_active:
                  type: boolean
                  default: true
                  description: 'Whether the preference is applied. Defaults to true when omitted.'
                  example: true
            examples:
              payUpTo:
                summary: 'Pay overtime up to 8 hours, bank the rest'
                value:
                  auto_decision_policy: force_auto_decision
                  policy_reason: 'Happy to be paid out for the first 8 hours'
                  preferred_decision: pay_up_to
                  max_hours: 8
                  rest_policy: add_to_balance
                  is_active: true
              incrementUpToSeconds:
                summary: 'Bank overtime up to 10 hours using seconds, drop the rest'
                value:
                  auto_decision_policy: skip_if_manual_decision
                  preferred_decision: increment_up_to
                  max_seconds: 36000
                  rest_policy: drop
              forceZeroOvertime:
                summary: 'Not eligible for overtime, other fields omitted'
                value:
                  auto_decision_policy: force_zero_overtime
                  policy_reason: 'Management contract, overtime not applicable'
              deactivate:
                summary: 'Keep the rule on record but stop applying it'
                value:
                  auto_decision_policy: force_auto_decision
                  preferred_decision: pay_up_to
                  max_hours: 8
                  rest_policy: add_to_balance
                  is_active: false
      responses:
        200:
          description: 'An existing preference was replaced.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - data
                  - meta
                properties:
                  message:
                    type: string
                    example: 'Your overtime decision preference has been saved.'
                  data:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreference'
                  meta:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreferenceMeta'
              example:
                message: 'Your overtime decision preference has been saved.'
                data:
                  id: 9b1f0c62-4d0a-4e2f-9f43-6f4a5c8d1e70
                  scope: employee
                  employee_id: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
                  auto_decision_policy: force_auto_decision
                  auto_decision_policy_label: 'Force auto-decision (override manual)'
                  policy_reason: 'Happy to be paid out for the first 8 hours'
                  preferred_decision: pay_up_to
                  preferred_decision_label: 'Pay up to X hours'
                  max_seconds: 28800
                  max_hours: 8
                  rest_policy: add_to_balance
                  rest_policy_label: 'Add to balance'
                  is_active: true
                  created_at: '2026-08-06 09:14:22'
                  updated_at: '2026-08-06 10:02:51'
                meta:
                  configured: true
                  options:
                    auto_decision_policy:
                      skip_if_manual_decision: 'Skip if manual decision exists'
                      force_auto_decision: 'Force auto-decision (override manual)'
                      force_zero_overtime: 'Force zero overtime (not eligible)'
                    preferred_decision:
                      pay_up_to: 'Pay up to X hours (specify max time)'
                      increment_up_to: 'Increment balance up to X hours (specify max time)'
                    rest_policy:
                      add_to_balance: 'Add to balance'
                      drop: 'Drop (ignore remaining hours)'
                  limits:
                    min_seconds: 3600
                    max_seconds: 115200
                    min_hours: 1
                    max_hours: 32
                  defaults:
                    auto_decision_policy: skip_if_manual_decision
                    preferred_decision: pay_up_to
                    rest_policy: add_to_balance
                    max_seconds: 3600
                    max_hours: 1
                    is_active: true
        201:
          description: 'The employee had no preference before and one was created.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - data
                  - meta
                properties:
                  message:
                    type: string
                    example: 'Your overtime decision preference has been saved.'
                  data:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreference'
                  meta:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreferenceMeta'
              example:
                message: 'Your overtime decision preference has been saved.'
                data:
                  id: 9b1f0c62-4d0a-4e2f-9f43-6f4a5c8d1e70
                  scope: employee
                  employee_id: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
                  auto_decision_policy: force_zero_overtime
                  auto_decision_policy_label: 'Force zero overtime (not eligible)'
                  policy_reason: 'Management contract, overtime not applicable'
                  preferred_decision: null
                  preferred_decision_label: null
                  max_seconds: null
                  max_hours: null
                  rest_policy: null
                  rest_policy_label: null
                  is_active: true
                  created_at: '2026-08-06 10:02:51'
                  updated_at: '2026-08-06 10:02:51'
                meta:
                  configured: true
                  options:
                    auto_decision_policy:
                      skip_if_manual_decision: 'Skip if manual decision exists'
                      force_auto_decision: 'Force auto-decision (override manual)'
                      force_zero_overtime: 'Force zero overtime (not eligible)'
                    preferred_decision:
                      pay_up_to: 'Pay up to X hours (specify max time)'
                      increment_up_to: 'Increment balance up to X hours (specify max time)'
                    rest_policy:
                      add_to_balance: 'Add to balance'
                      drop: 'Drop (ignore remaining hours)'
                  limits:
                    min_seconds: 3600
                    max_seconds: 115200
                    min_hours: 1
                    max_hours: 32
                  defaults:
                    auto_decision_policy: skip_if_manual_decision
                    preferred_decision: pay_up_to
                    rest_policy: add_to_balance
                    max_seconds: 3600
                    max_hours: 1
                    is_active: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'The body failed validation.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - errors
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
              examples:
                missingCap:
                  summary: 'Neither max_hours nor max_seconds was sent'
                  value:
                    message: 'The given data was invalid.'
                    errors:
                      max_hours:
                        - 'A maximum number of hours is required for the selected preferred decision.'
                missingPreferredDecision:
                  summary: 'preferred_decision and rest_policy omitted on a policy that needs them'
                  value:
                    message: 'The given data was invalid.'
                    errors:
                      preferred_decision:
                        - 'The preferred decision field is required unless auto decision policy is in force_zero_overtime.'
                      rest_policy:
                        - 'The rest policy field is required unless auto decision policy is in force_zero_overtime.'
                outOfRange:
                  summary: 'The cap is outside the accepted 1 to 32 hour range'
                  value:
                    message: 'The given data was invalid.'
                    errors:
                      max_seconds:
                        - 'The max seconds field must not be greater than 115200.'
                badEnum:
                  summary: 'An unknown enum value was sent'
                  value:
                    message: 'The given data was invalid.'
                    errors:
                      auto_decision_policy:
                        - 'The selected auto decision policy is invalid.'
    delete:
      tags:
        - TempusOvertime
      summary: "Remove the employee's overtime decision preference (user)"
      operationId: tempusDeleteUserOvertimeDecisionPreference
      description: |
        Removes the employee level preference so the company level rule applies again. The row is soft deleted, so a later save creates a fresh one.

        Returns 404 when the employee has no preference to remove.

        Self service only. The request is rejected with 403 when the authenticated user has no access to the tenant or the employee record is not their own.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: "UUID of the employee. Must be the authenticated user's own employee record."
          schema:
            type: string
            format: uuid
          example: a24c68c0-92c0-4ca0-b749-84c6ddd671ed
      responses:
        200:
          description: 'The preference was removed.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                  - data
                  - meta
                properties:
                  message:
                    type: string
                    example: 'Your overtime decision preference has been removed.'
                  data:
                    type: 'null'
                  meta:
                    $ref: '#/components/schemas/TempusOvertimeDecisionPreferenceMeta'
              example:
                message: 'Your overtime decision preference has been removed.'
                data: null
                meta:
                  configured: false
                  options:
                    auto_decision_policy:
                      skip_if_manual_decision: 'Skip if manual decision exists'
                      force_auto_decision: 'Force auto-decision (override manual)'
                      force_zero_overtime: 'Force zero overtime (not eligible)'
                    preferred_decision:
                      pay_up_to: 'Pay up to X hours (specify max time)'
                      increment_up_to: 'Increment balance up to X hours (specify max time)'
                    rest_policy:
                      add_to_balance: 'Add to balance'
                      drop: 'Drop (ignore remaining hours)'
                  limits:
                    min_seconds: 3600
                    max_seconds: 115200
                    min_hours: 1
                    max_hours: 32
                  defaults:
                    auto_decision_policy: skip_if_manual_decision
                    preferred_decision: pay_up_to
                    rest_policy: add_to_balance
                    max_seconds: 3600
                    max_hours: 1
                    is_active: true
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to the requested tenant, or the requested employee record does not belong to the authenticated user.
        404:
          description: 'The employee was not found, or has no overtime decision preference to remove.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                properties:
                  message:
                    type: string
                    example: 'No overtime decision preference has been set for this employee.'
  '/{pbx_id}/users-overtime-decisions':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusOvertime
      summary: 'List overtime decisions for all employees (user)'
      operationId: tempusListUsersOvertimeDecisions
      description: |
        Returns a paginated list of overtime decisions across all Tempus employees in the PBX tenant (the administrative view). Each item is serialized by the `UserOvertimeDecisionResource`. The caller must be authorized to view all overtime decisions for the tenant, otherwise the request is rejected with 403. Results may be filtered by overtime calculation period, decision type, lock state and company, and are sorted by `-created_at` by default.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[overtime_calculation_period_id]'
          in: query
          required: false
          description: 'Restrict results to a single overtime calculation period.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440060
        -
          name: 'filter[decision_type]'
          in: query
          required: false
          description: |
            Restrict results to one or more decision types. Accepts a single value or a comma-separated list (for example `manual,automatic`).
          schema:
            type: string
          example: manual
        -
          name: 'filter[lock_states]'
          in: query
          required: false
          description: |
            Restrict results by lock state. `locked` returns processed (locked) decisions, `unlocked` returns decisions that have not been processed.
          schema:
            type: string
            enum:
              - locked
              - unlocked
          example: unlocked
        -
          name: 'filter[company_id]'
          in: query
          required: false
          description: 'Restrict results to a single Tempus company.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          example: 20
      responses:
        200:
          description: 'Paginated list of overtime decisions for all employees.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusUserOvertimeDecision'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The caller is not authorized to view overtime decisions for this tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/overtime-calculation-periods':
    get:
      tags:
        - TempusOvertime
      summary: 'List overtime calculation periods for a tenant (user)'
      operationId: tempusListOvertimeCalculationPeriods
      description: |
        Returns a paginated list of overtime calculation periods belonging to the PBX tenant, ordered by start date descending. Each item is serialized by the `OvertimeCalculationPeriodResource`. The caller must be authorized to view overtime periods for the tenant, otherwise the request is rejected with 403. Results may be filtered by company, by start/end date bounds and by lock state.

        This endpoint is served under the standard `/api/v1` host (not the Tempus host).
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[company_id]'
          in: query
          required: false
          description: 'Restrict results to a single Tempus company.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Only include periods whose start date is on or after this date.'
          schema:
            type: string
            format: date
          example: '2024-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Only include periods whose end date is on or before this date.'
          schema:
            type: string
            format: date
          example: '2024-12-31'
        -
          name: 'filter[locked]'
          in: query
          required: false
          description: |
            Filter by lock state. A truthy value returns only locked periods; a falsy value returns all periods that are not locked.
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
              - '1'
              - '0'
          example: 'false'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 15
          example: 15
      responses:
        200:
          description: 'Paginated list of overtime calculation periods.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusOvertimeCalculationPeriod'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The caller is not authorized to view overtime periods for this tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/work-times':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusWorkTimes
      summary: 'List weekly work times for employees in the tenant (user)'
      operationId: tempusListWorkTimes
      description: |
        Returns a paginated map of weekly work-time aggregates for active employees in the PBX tenant. The response uses a hand-rolled Laravel paginator envelope (`data`, `links`, `meta`). The `data` object is keyed by employee UUID; each value is a map keyed by ISO week-start date (`YYYY-MM-DD`) plus a reserved `summary` key holding the totals across the queried range. Time values are formatted strings (`HH:MM:SS`) or `-` when no work shift was compiled for that week, and every one is mirrored by a signed `<field>Seconds` integer. Overtime figures are **balances**: a week below the required time is negative, so the weekly rows always sum to `summary`. Days after today are excluded from the aggregates (they would otherwise book a full requirement against zero worked time), so a still-running overtime period reports the same balance as `GET /{pbx_id}/user/{employee_id}/overtime`. When the authenticated user cannot view other employees (no validator scope) and no `filter[employee_id]` or `user_ids` is supplied, the result is scoped to the caller's own employee record; requesting another employee returns 403. The queried date range defaults to the current month and cannot exceed 100 days.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Start date of the range (format `Y-m-d`). Defaults to the first day of the current month.'
          schema:
            type: string
            format: date
          example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'End date of the range (format `Y-m-d`). Defaults to today. The range may not exceed 100 days.'
          schema:
            type: string
            format: date
          example: '2024-03-31'
        -
          name: 'filter[employee_id]'
          in: query
          required: false
          description: 'One or more employee UUIDs to restrict the result to. Accepts a comma-separated string or an array.'
          schema:
            type: array
            items:
              type: string
              format: uuid
          example:
            - 550e8400-e29b-41d4-a716-446655440001
        -
          name: user_ids
          in: query
          required: false
          description: 'Array of employee UUIDs to restrict the result to.'
          schema:
            type: array
            items:
              type: string
              format: uuid
          example:
            - 550e8400-e29b-41d4-a716-446655440001
        -
          name: page
          in: query
          required: false
          description: 'Page number.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of employees per page (1 to 100, default 20).'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 20
      responses:
        200:
          description: |
            OK. Paginated envelope. The `data` object is keyed by employee UUID; each value is a weekly map keyed by week-start date plus a `summary` key.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: 'Map keyed by employee UUID. Each value is a weekly work-time map.'
                    additionalProperties:
                      type: object
                      description: |
                        Map keyed by week-start date (`YYYY-MM-DD`) plus a reserved `summary` key. Each value is a weekly work-time aggregate.
                      additionalProperties:
                        type: object
                        description: 'Aggregated work-time figures for a single week or the range summary.'
                        properties:
                          totalWorkedTime:
                            type: string
                            description: 'Total worked time, formatted as `HH:MM:SS` (hours may exceed two digits).'
                            example: '40:00:00'
                          totalWorkedTimeSeconds:
                            type: integer
                            description: 'Same figure in seconds.'
                            example: 144000
                          requiredWorkedTime:
                            type: string
                            description: 'Minimum required worked time as `HH:MM:SS`, or `-` when no work shift was compiled.'
                            example: '40:00:00'
                          requiredWorkedTimeSeconds:
                            type: integer
                            description: 'Same figure in seconds; `0` when `requiredWorkedTime` is `-`.'
                            example: 144000
                          businessDaysWorkedTime:
                            type: string
                            description: |
                              Overtime balance on business days as `HH:MM:SS`, or `-` when no work shift was compiled. **Signed**: a week below the required time is negative (`-02:08:49`), so the weekly rows sum to the range total.
                            example: '-02:08:49'
                          businessDaysWorkedTimeSeconds:
                            type: integer
                            description: |
                              Same balance in seconds, negative for undertime; `0` when `businessDaysWorkedTime` is `-`. Sum this field rather than parsing the string.
                            example: -7729
                          nonWorkingDaysWorkedTime:
                            type: string
                            description: 'Overtime balance on non-working days as `HH:MM:SS` (signed), or `-` when no work shift was compiled.'
                            example: '00:00:00'
                          nonWorkingDaysWorkedTimeSeconds:
                            type: integer
                            description: 'Same balance in seconds; `0` when `nonWorkingDaysWorkedTime` is `-`.'
                            example: 0
                          hasOvertime:
                            type: boolean
                            description: 'Whether the week recorded any overtime.'
                            example: false
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
              example:
                data:
                  550e8400-e29b-41d4-a716-446655440001:
                    '2024-03-04':
                      totalWorkedTime: '41:31:51'
                      totalWorkedTimeSeconds: 149511
                      requiredWorkedTime: '40:00:00'
                      requiredWorkedTimeSeconds: 144000
                      businessDaysWorkedTime: '01:31:51'
                      businessDaysWorkedTimeSeconds: 5511
                      nonWorkingDaysWorkedTime: '00:00:00'
                      nonWorkingDaysWorkedTimeSeconds: 0
                      hasOvertime: true
                    '2024-03-11':
                      totalWorkedTime: '37:51:11'
                      totalWorkedTimeSeconds: 136271
                      requiredWorkedTime: '40:00:00'
                      requiredWorkedTimeSeconds: 144000
                      businessDaysWorkedTime: '-02:08:49'
                      businessDaysWorkedTimeSeconds: -7729
                      nonWorkingDaysWorkedTime: '00:00:00'
                      nonWorkingDaysWorkedTimeSeconds: 0
                      hasOvertime: false
                    summary:
                      totalWorkedTime: '79:23:02'
                      totalWorkedTimeSeconds: 285782
                      requiredWorkedTime: '80:00:00'
                      requiredWorkedTimeSeconds: 288000
                      businessDaysWorkedTime: '-00:36:58'
                      businessDaysWorkedTimeSeconds: -2218
                      nonWorkingDaysWorkedTime: '00:00:00'
                      nonWorkingDaysWorkedTimeSeconds: 0
                      hasOvertime: false
                links:
                  first: 'https://cockpit.voxbi.com/tempus/api/v1/550e8400-e29b-41d4-a716-446655440000/work-times?page=1'
                  last: 'https://cockpit.voxbi.com/tempus/api/v1/550e8400-e29b-41d4-a716-446655440000/work-times?page=1'
                  prev: null
                  next: null
                meta:
                  current_page: 1
                  from: 1
                  last_page: 1
                  path: 'https://cockpit.voxbi.com/tempus/api/v1/550e8400-e29b-41d4-a716-446655440000/work-times'
                  per_page: 20
                  to: 1
                  total: 1
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no associated employee record, belongs to a different PBX, or requested work times for an employee they are not allowed to view.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/work-times':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusWorkTimes
      summary: 'List weekly work times for a single employee (user)'
      operationId: tempusListUserWorkTimes
      description: |
        Returns the weekly work-time aggregates for one employee. The response is a flat object (NOT wrapped in `data`) keyed by ISO week-start date (`YYYY-MM-DD`) plus a reserved `summary` key holding the totals across the queried range. Time values are formatted strings (`HH:MM:SS`) or `-` when no work shift was compiled for that week, and every one is mirrored by a signed `<field>Seconds` integer. Overtime figures are **balances**: a week below the required time is negative, so the weekly rows always sum to `summary`. Days after today are excluded from the aggregates (they would otherwise book a full requirement against zero worked time), so a still-running overtime period reports the same balance as `GET /{pbx_id}/user/{employee_id}/overtime`. Each entry also includes a `minWorkTimeReached` boolean. The caller may only request their own employee record; requesting another employee returns 403. The queried date range defaults to the current month and cannot exceed 100 days.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: "UUID of the employee. Must match the authenticated caller's own employee record."
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Start date of the range (format `Y-m-d`). Defaults to the first day of the current month.'
          schema:
            type: string
            format: date
          example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'End date of the range (format `Y-m-d`). Defaults to today. The range may not exceed 100 days.'
          schema:
            type: string
            format: date
          example: '2024-03-31'
      responses:
        200:
          description: |
            OK. Flat object keyed by week-start date (`YYYY-MM-DD`) plus a reserved `summary` key. NOT wrapped in `data`.
          content:
            application/json:
              schema:
                type: object
                description: 'Map keyed by week-start date plus a reserved `summary` key.'
                additionalProperties:
                  type: object
                  description: 'Aggregated work-time figures for a single week or the range summary.'
                  properties:
                    totalWorkedTime:
                      type: string
                      description: 'Total worked time, formatted as `HH:MM:SS` (hours may exceed two digits).'
                      example: '40:00:00'
                    totalWorkedTimeSeconds:
                      type: integer
                      description: 'Same figure in seconds.'
                      example: 144000
                    requiredWorkedTime:
                      type: string
                      description: 'Minimum required worked time as `HH:MM:SS`, or `-` when no work shift was compiled.'
                      example: '40:00:00'
                    requiredWorkedTimeSeconds:
                      type: integer
                      description: 'Same figure in seconds; `0` when `requiredWorkedTime` is `-`.'
                      example: 144000
                    businessDaysWorkedTime:
                      type: string
                      description: |
                        Overtime balance on business days as `HH:MM:SS`, or `-` when no work shift was compiled. **Signed**: a week below the required time is negative (`-02:08:49`), so the weekly rows sum to the range total.
                      example: '-02:08:49'
                    businessDaysWorkedTimeSeconds:
                      type: integer
                      description: |
                        Same balance in seconds, negative for undertime; `0` when `businessDaysWorkedTime` is `-`. Sum this field rather than parsing the string.
                      example: -7729
                    nonWorkingDaysWorkedTime:
                      type: string
                      description: 'Overtime balance on non-working days as `HH:MM:SS` (signed), or `-` when no work shift was compiled.'
                      example: '00:00:00'
                    nonWorkingDaysWorkedTimeSeconds:
                      type: integer
                      description: 'Same balance in seconds; `0` when `nonWorkingDaysWorkedTime` is `-`.'
                      example: 0
                    hasOvertime:
                      type: boolean
                      description: 'Whether the week recorded any overtime.'
                      example: false
                    minWorkTimeReached:
                      type: boolean
                      description: 'Whether total worked time met or exceeded the required worked time.'
                      example: true
              example:
                '2024-03-04':
                  totalWorkedTime: '41:31:51'
                  totalWorkedTimeSeconds: 149511
                  requiredWorkedTime: '40:00:00'
                  requiredWorkedTimeSeconds: 144000
                  businessDaysWorkedTime: '01:31:51'
                  businessDaysWorkedTimeSeconds: 5511
                  nonWorkingDaysWorkedTime: '00:00:00'
                  nonWorkingDaysWorkedTimeSeconds: 0
                  hasOvertime: true
                  minWorkTimeReached: true
                '2024-03-11':
                  totalWorkedTime: '37:51:11'
                  totalWorkedTimeSeconds: 136271
                  requiredWorkedTime: '40:00:00'
                  requiredWorkedTimeSeconds: 144000
                  businessDaysWorkedTime: '-02:08:49'
                  businessDaysWorkedTimeSeconds: -7729
                  nonWorkingDaysWorkedTime: '00:00:00'
                  nonWorkingDaysWorkedTimeSeconds: 0
                  hasOvertime: false
                  minWorkTimeReached: false
                summary:
                  totalWorkedTime: '79:23:02'
                  totalWorkedTimeSeconds: 285782
                  requiredWorkedTime: '80:00:00'
                  requiredWorkedTimeSeconds: 288000
                  businessDaysWorkedTime: '-00:36:58'
                  businessDaysWorkedTimeSeconds: -2218
                  nonWorkingDaysWorkedTime: '00:00:00'
                  nonWorkingDaysWorkedTimeSeconds: 0
                  hasOvertime: false
                  minWorkTimeReached: false
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no associated employee record, belongs to a different PBX, or requested an employee other than their own.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/required-work-time':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusWorkTimes
      summary: 'Get daily required work time for a single employee (user)'
      operationId: tempusGetUserRequiredWorkTime
      description: |
        Returns the contracted (required) work time per calendar day for one employee across the requested range. The response is a flat object (NOT wrapped in `data`) keyed by date (`YYYY-MM-DD`); each value is the required work time for that day in seconds. The figure is derived from the employee's active work-shift assignment and is reduced by approved absences and public holidays (full-day holidays yield 0, half-day holidays halve the requirement). Values are never negative. Both `filter[from]` and `filter[to]` are required and the range may not exceed 100 days. The caller may only request their own employee record; requesting another employee returns 403.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: "UUID of the employee. Must match the authenticated caller's own employee record."
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: true
          description: 'Start date of the range (format `Y-m-d`).'
          schema:
            type: string
            format: date
          example: '2024-03-01'
        -
          name: 'filter[to]'
          in: query
          required: true
          description: 'End date of the range (format `Y-m-d`). The range may not exceed 100 days.'
          schema:
            type: string
            format: date
          example: '2024-03-31'
      responses:
        200:
          description: |
            OK. Flat object keyed by date (`YYYY-MM-DD`); each value is the required work time in seconds for that day. NOT wrapped in `data`.
          content:
            application/json:
              schema:
                type: object
                description: 'Map keyed by date. Each value is the required work time for that day in seconds.'
                additionalProperties:
                  type: integer
                  description: 'Required work time for the day in seconds (never negative).'
                  example: 28800
              example:
                '2024-03-01': 28800
                '2024-03-02': 0
                '2024-03-03': 0
                '2024-03-04': 28800
                '2024-03-05': 14400
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no associated employee record, belongs to a different PBX, or requested an employee other than their own.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/groups':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusEmployees
      summary: 'List departments for the tenant (user)'
      operationId: tempusListDepartments
      description: |
        Returns a paginated list of departments (also called groups) belonging to the PBX tenant. Each item is serialized by the V1 `TempusDepartmentResource`. Departments are a per-tenant catalog of organizational units used across the Tempus time and attendance module. The authenticated user must belong to the PBX identified by the path parameter, otherwise the request is rejected with 403. Results are paginated using standard Laravel pagination.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 15
      responses:
        200:
          description: 'Paginated list of departments.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusDepartment'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user does not belong to the requested PBX tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/departments':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusEmployees
      summary: 'List departments for the tenant (user)'
      operationId: listDepartments
      description: |
        Returns the full list of departments belonging to the PBX tenant, each serialized by the V1 `DepartmentResource` with clean field names (id, name, description). Departments are a per-tenant catalog of organizational units used across the Tempus time and attendance module. The authenticated user must belong to the PBX identified by the path parameter, otherwise the request is rejected with 403. The result is not paginated: the complete list is returned as a top-level array. This is the properly named replacement for the legacy `groups` endpoint, which returns the same records under legacy key names.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        200:
          description: 'List of departments.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TempusDepartmentBasic'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user does not belong to the requested PBX tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/user/{employee_id}/timepoints':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusEmployees
      summary: 'List timepoints for an employee (user)'
      operationId: tempusListUserTimepoints
      description: |
        Returns a paginated list of clock-in/clock-out timepoints recorded for a single employee, newest first. The authenticated user must have access to the PBX tenant and be authorized to view the target employee's records. An optional date window can be applied with `filter[from]` and `filter[to]`; when both are supplied, `filter[from]` must not be after `filter[to]` and the range may not exceed 100 days, otherwise the request is rejected with 422. Each item is returned in the legacy timepoint shape (id, ext_id, time, status, comment, GPS coordinates, and an optional sub-status).

        Three independent pieces of location data are returned and must not be conflated: `location` is the configured location record the employee selected; `gpsLat` / `gpsLong` / `gpsTimestamp` and the normalised `device_gps` block are where the device said it was, stored exactly as the client reported it; `location_check` compares the two and carries the geofence verdict (`match` / `mismatch` / `unknown`). The device coordinates are never replaced by the coordinates configured on the location.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee whose timepoints are listed.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: 'filter[from]'
          in: query
          required: false
          description: 'Return timepoints whose start time is on or after this date (Y-m-d).'
          schema:
            type: string
            format: date
          example: '2026-01-01'
        -
          name: 'filter[to]'
          in: query
          required: false
          description: 'Return timepoints whose start time is on or before this date (Y-m-d).'
          schema:
            type: string
            format: date
          example: '2026-01-31'
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 500
          example: 15
      responses:
        200:
          description: 'Paginated list of employee timepoints.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusUserTimepointLegacy'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user has no access to this PBX tenant or is not authorized to view the target employee's records.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/user/{employee_id}/timepoints/{id}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    delete:
      tags:
        - TempusEmployees
      summary: 'Delete a timepoint for an employee (user)'
      operationId: tempusDeleteUserTimepoint
      description: |
        Permanently deletes a single timepoint belonging to the specified employee within the PBX tenant. The timepoint must exist for the tenant and must belong to the given employee, otherwise a 404 is returned. The authenticated user must be authorized by the timepoint delete policy for this tenant; if not, a 403 is returned.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: employee_id
          in: path
          required: true
          description: 'UUID of the employee that owns the timepoint.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: id
          in: path
          required: true
          description: 'UUID of the timepoint to delete.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440070
      responses:
        204:
          description: 'Timepoint deleted. No content is returned.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user is not authorized to delete this timepoint.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/schedules':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'List schedules for the tenant (user)'
      operationId: tempusListSchedules
      description: |
        Returns a paginated list of active Tempus schedules (planning grids) for the PBX tenant. Only schedules whose owning department belongs to the tenant and whose `is_active` flag is true are returned, ordered alphabetically by name. Each item is a `TempusScheduleSummary` as serialized by the `ScheduleResource`, with its owning department embedded under the `group` key. Results can be narrowed to one or more departments with the `filter[group_id]` query parameter.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: 'filter[group_id]'
          in: query
          required: false
          description: |
            Comma-separated list of department (group) UUIDs to restrict results to. Only schedules belonging to these departments are returned.
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440002
        -
          name: page
          in: query
          required: false
          description: 'Page number to retrieve.'
          schema:
            type: integer
            minimum: 1
          example: 1
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
          example: 100
      responses:
        200:
          description: 'Paginated list of active schedules for the tenant.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusScheduleSummary'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'List managed schedules for the tenant (user)'
      operationId: tempusListManagedSchedules
      description: |
        Returns a paginated list of the tenant's schedules. Reading is open to any authenticated user of the PBX; write access stays gated by the caller's schedules-management validator scope. Use the `search` parameter to filter by schedule name and `is_active` to filter by active state.

        Each item carries its scope: `scopeType` plus the raw `scope` selection, the resolved `departments`, and the `employees` who may be booked into its slots.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: search
          in: query
          required: false
          description: 'Filter schedules whose name contains this string.'
          schema:
            type: string
            maxLength: 200
          example: Reception
        -
          name: is_active
          in: query
          required: false
          description: 'Filter by active state. Accepts boolean-like values.'
          schema:
            type: boolean
          example: true
        -
          name: per_page
          in: query
          required: false
          description: 'Number of items per page (capped at 100).'
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 15
          example: 15
      responses:
        200:
          description: 'Paginated list of managed schedules.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusScheduleManagement'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The first page of the resource'
                      last:
                        type: string
                        example: 'http://localhost/api/v1/resources?page=1'
                        description: 'The last page of the resource'
                      prev:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The previous page of the resource'
                      next:
                        type:
                          - 'null'
                          - string
                        example: null
                        description: 'The next page of the resource'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The current page of the resource'
                      from:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The first item of the resource'
                      last_page:
                        type: integer
                        minimum: 1
                        example: 1
                        description: 'The last page of the resource'
                      links:
                        type: array
                        items:
                          properties:
                            url:
                              type:
                                - string
                                - 'null'
                              example: 'http://localhost/api/v1/resources?page=1'
                              description: 'The url of the resource (null for the boundary prev/next links)'
                            label:
                              type: string
                              example: first
                              description: 'The label of the resource'
                            active:
                              type: boolean
                              example: true
                              description: 'The status of the resource'
                          type: object
                      path:
                        type: string
                        example: 'http://localhost/api/v1/resources'
                        description: 'The path of the resource'
                      per_page:
                        type: integer
                        minimum: 1
                        example: 15
                        description: 'The number of items per page of the resource'
                      to:
                        type:
                          - 'null'
                          - integer
                        minimum: 1
                        example: 1
                        description: 'The last item of the resource'
                      total:
                        type: integer
                        minimum: 0
                        example: 1
                        description: 'The total number of items of the resource'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    post:
      tags:
        - TempusSchedules
      summary: 'Create a schedule (user)'
      operationId: tempusCreateManagedSchedule
      description: |
        Creates a schedule. Requires a token whose validator holds the schedules-management permission, and every company, department or employee you select must be within that validator scope.

        `scope_type` decides who the schedule is for and which selection field is required. It is optional: omit it and the `department_id` you send becomes a single-department scope, which is exactly how this endpoint behaved before scopes existed, so existing integrations need no change.

        The schedule's anchor department (`department` in the response, `group_id` on the legacy list endpoint) is derived from the selection. When the selection resolves to no department at all, which happens for a company whose people hold contracts carrying no department, the schedule is saved without one and works normally: its people come from the company. Nothing is refused for lack of a department.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - days_of_week
                - day_start_time
                - day_end_time
              properties:
                name:
                  type: string
                  maxLength: 150
                  description: 'Display name of the schedule.'
                  example: 'Reception weekdays'
                scope_type:
                  type: string
                  enum:
                    - company
                    - department
                    - employees
                  default: department
                  description: |
                    Who the schedule is for. Optional: when omitted the request behaves exactly as before scopes existed and `department_id` becomes the scope.
                  example: department
                companies:
                  type: array
                  minItems: 1
                  description: |
                    Companies the schedule covers. Required when `scope_type` is `company`. Everyone currently contracted with these companies may be assigned, whether or not their contract carries a department. Each company must belong to your PBX and be within your validator scope.
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a company.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440020
                departments:
                  type: array
                  minItems: 1
                  description: |
                    Departments the schedule covers, replacing the single `department_id`. Used when `scope_type` is `department`; either this or `department_id` is required in that case. Each department must belong to your PBX and be within your validator scope.
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a department.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440001
                    - 550e8400-e29b-41d4-a716-446655440002
                employees:
                  type: array
                  minItems: 1
                  description: |
                    The exact people the schedule covers. Required when `scope_type` is `employees`. They may come from different departments and different companies. Each employee must be within your validator scope. The selection is stored as sent, but only those under a contract that is active today are actually assignable and returned in `employees`.
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an employee.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
                department_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    The legacy single department. Required only when you send neither `scope_type` nor `departments`. Ignored for a company or employee scope, where the anchor department is derived from the selection.
                  example: 550e8400-e29b-41d4-a716-446655440001
                days_of_week:
                  type: array
                  minItems: 1
                  description: 'Weekdays the schedule covers.'
                  items:
                    type: integer
                    minimum: 1
                    maximum: 7
                    description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                  example:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                day_start_time:
                  type: string
                  description: 'Start of the daily window as `HH:MM`.'
                  example: '08:00'
                day_end_time:
                  type: string
                  description: 'End of the daily window as `HH:MM`. Must be after day_start_time.'
                  example: '17:00'
                status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default status for generated entries. Must belong to your PBX.'
                  example: 550e8400-e29b-41d4-a716-446655440003
                sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default sub-status. Must belong to the selected status.'
                  example: null
                status_filters:
                  type: array
                  description: 'Statuses selectable on the grid. Each must belong to your PBX.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an allowed status.'
                  example: {}
                is_active:
                  type: boolean
                  default: true
                  description: 'Whether the schedule is active.'
                  example: true
            examples:
              departmentScope:
                summary: 'Several departments'
                value:
                  name: 'Reception weekdays'
                  scope_type: department
                  departments:
                    - 550e8400-e29b-41d4-a716-446655440001
                    - 550e8400-e29b-41d4-a716-446655440002
                  days_of_week:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                  day_start_time: '08:00'
                  day_end_time: '17:00'
              companyScope:
                summary: 'Whole companies'
                value:
                  name: 'Group-wide on-call'
                  scope_type: company
                  companies:
                    - 550e8400-e29b-41d4-a716-446655440020
                  days_of_week:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                    - 7
                  day_start_time: '00:00'
                  day_end_time: '23:30'
              employeeScope:
                summary: 'A hand-picked team'
                value:
                  name: 'Weekend duty team'
                  scope_type: employees
                  employees:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
                  days_of_week:
                    - 6
                    - 7
                  day_start_time: '09:00'
                  day_end_time: '18:00'
              legacySingleDepartment:
                summary: 'Pre-scope request, still supported unchanged'
                value:
                  name: 'Reception weekdays'
                  department_id: 550e8400-e29b-41d4-a716-446655440001
                  days_of_week:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                  day_start_time: '08:00'
                  day_end_time: '17:00'
      responses:
        201:
          description: 'The created schedule.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusScheduleManagement'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The caller has no schedules-management scope, or the selection reaches beyond it. The message is "You do not have permission to manage schedules for this department." for a department (or a department resolved from a selected company) outside the scope, and "You do not have permission to manage this employee." for an employee outside it.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management/{schedule}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'Get a managed schedule (user)'
      operationId: tempusGetManagedSchedule
      description: |
        Returns the detail of a single schedule with its `department`, `status`, and `subStatus` relations resolved, plus its scope: `scopeType`, the raw `scope` selection, the resolved `departments`, and the `employees` who may be booked into its slots. Reading is open to any authenticated user of the PBX; a schedule in another tenant returns 404.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'The requested schedule.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusScheduleManagement'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The authenticated user is outside the requested tenant.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
    put:
      tags:
        - TempusSchedules
      summary: 'Update a schedule (user)'
      operationId: tempusUpdateManagedSchedule
      description: |
        Updates a schedule. Every field is optional: send only what changes. The caller must hold the schedules-management permission and manage at least some of the schedule's people; otherwise a 404 is returned.

        Scope: send `scope_type` with the matching selection to change who the schedule is for. The new selection REPLACES the previous one. An update that mentions none of `scope_type`, `companies`, `departments`, `employees` or `department_id` leaves the scope exactly as it was, so a plain rename is safe. `day_start_time` and `day_end_time` must be sent together.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 150
                  description: 'Display name of the schedule.'
                  example: 'Reception (summer)'
                scope_type:
                  type: string
                  enum:
                    - company
                    - department
                    - employees
                  description: |
                    Change who the schedule is for. Send it together with the matching selection; the new selection REPLACES the old one, so switching a department schedule to `employees` drops its departments.
                  example: employees
                companies:
                  type: array
                  minItems: 1
                  description: 'Companies the schedule covers. Required when `scope_type` is `company`.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a company.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440020
                departments:
                  type: array
                  minItems: 1
                  description: 'Departments the schedule covers. Used when `scope_type` is `department`.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a department.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440001
                employees:
                  type: array
                  minItems: 1
                  description: |
                    The exact people the schedule covers. Required when `scope_type` is `employees`.
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an employee.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440010
                department_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Move the schedule's anchor department. The target must be within your validator scope.
                  example: 550e8400-e29b-41d4-a716-446655440001
                days_of_week:
                  type: array
                  minItems: 1
                  description: 'Weekdays the schedule covers.'
                  items:
                    type: integer
                    minimum: 1
                    maximum: 7
                    description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                  example:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                day_start_time:
                  type: string
                  description: |
                    Start of the daily window as `HH:MM`. Must be sent together with day_end_time.
                  example: '08:00'
                day_end_time:
                  type: string
                  description: |
                    End of the daily window as `HH:MM`. Must be after day_start_time and sent together with it.
                  example: '17:00'
                status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default status for generated entries. Must belong to your PBX.'
                  example: 550e8400-e29b-41d4-a716-446655440003
                sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default sub-status. Must belong to the selected status.'
                  example: null
                status_filters:
                  type: array
                  description: 'Statuses selectable on the grid. Each must belong to your PBX.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an allowed status.'
                  example: {}
                is_active:
                  type: boolean
                  description: 'Whether the schedule is active.'
                  example: false
            examples:
              renameOnly:
                summary: 'Rename, leaving the scope untouched'
                value:
                  name: 'Reception (summer)'
              reScope:
                summary: 'Switch to a hand-picked team, replacing the old selection'
                value:
                  scope_type: employees
                  employees:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
      responses:
        200:
          description: 'The updated schedule.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusScheduleManagement'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The caller has no schedules-management scope, or the new selection reaches beyond it. The message is "You do not have permission to manage schedules for this department." for a department (or one resolved from a selected company) outside the scope, and "You do not have permission to manage this employee." for an employee outside it.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    patch:
      tags:
        - TempusSchedules
      summary: 'Partially update a schedule (user)'
      operationId: tempusPatchManagedSchedule
      description: |
        Updates a schedule. Every field is optional: send only what changes. The caller must hold the schedules-management permission and manage at least some of the schedule's people; otherwise a 404 is returned.

        Scope: send `scope_type` with the matching selection to change who the schedule is for. The new selection REPLACES the previous one. An update that mentions none of `scope_type`, `companies`, `departments`, `employees` or `department_id` leaves the scope exactly as it was, so a plain rename is safe. `day_start_time` and `day_end_time` must be sent together.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 150
                  description: 'Display name of the schedule.'
                  example: 'Reception (summer)'
                scope_type:
                  type: string
                  enum:
                    - company
                    - department
                    - employees
                  description: |
                    Change who the schedule is for. Send it together with the matching selection; the new selection REPLACES the old one, so switching a department schedule to `employees` drops its departments.
                  example: employees
                companies:
                  type: array
                  minItems: 1
                  description: 'Companies the schedule covers. Required when `scope_type` is `company`.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a company.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440020
                departments:
                  type: array
                  minItems: 1
                  description: 'Departments the schedule covers. Used when `scope_type` is `department`.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of a department.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440001
                employees:
                  type: array
                  minItems: 1
                  description: |
                    The exact people the schedule covers. Required when `scope_type` is `employees`.
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an employee.'
                  example:
                    - 550e8400-e29b-41d4-a716-446655440010
                department_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: |
                    Move the schedule's anchor department. The target must be within your validator scope.
                  example: 550e8400-e29b-41d4-a716-446655440001
                days_of_week:
                  type: array
                  minItems: 1
                  description: 'Weekdays the schedule covers.'
                  items:
                    type: integer
                    minimum: 1
                    maximum: 7
                    description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                  example:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                day_start_time:
                  type: string
                  description: |
                    Start of the daily window as `HH:MM`. Must be sent together with day_end_time.
                  example: '08:00'
                day_end_time:
                  type: string
                  description: |
                    End of the daily window as `HH:MM`. Must be after day_start_time and sent together with it.
                  example: '17:00'
                status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default status for generated entries. Must belong to your PBX.'
                  example: 550e8400-e29b-41d4-a716-446655440003
                sub_status_id:
                  type:
                    - string
                    - 'null'
                  format: uuid
                  description: 'Default sub-status. Must belong to the selected status.'
                  example: null
                status_filters:
                  type: array
                  description: 'Statuses selectable on the grid. Each must belong to your PBX.'
                  items:
                    type: string
                    format: uuid
                    description: 'UUID of an allowed status.'
                  example: {}
                is_active:
                  type: boolean
                  description: 'Whether the schedule is active.'
                  example: false
            examples:
              renameOnly:
                summary: 'Rename, leaving the scope untouched'
                value:
                  name: 'Reception (summer)'
              reScope:
                summary: 'Switch to a hand-picked team, replacing the old selection'
                value:
                  scope_type: employees
                  employees:
                    - 550e8400-e29b-41d4-a716-446655440010
                    - 550e8400-e29b-41d4-a716-446655440011
      responses:
        200:
          description: 'The updated schedule.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TempusScheduleManagement'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The caller has no schedules-management scope, or the new selection reaches beyond it. The message is "You do not have permission to manage schedules for this department." for a department (or one resolved from a selected company) outside the scope, and "You do not have permission to manage this employee." for an employee outside it.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - TempusSchedules
      summary: 'Delete a schedule (user)'
      operationId: tempusDeleteManagedSchedule
      description: |
        Soft-deletes a schedule and cascades to its slots. Refused with a 422 while the schedule still has assigned entries: clear those first. The caller must hold the schedules-management permission and manage at least some of the schedule's people.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'The schedule was deleted.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: 'Confirmation message.'
                    example: 'Schedule deleted successfully.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'The caller has no schedules-management scope.'
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: |
            The schedule still has assigned entries. Body is `{"message": "This schedule has assigned entries and cannot be deleted. Remove the entries first."}`.
  '/{pbx_id}/schedule-management/{schedule}/employees':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'List the employees a schedule may assign (user)'
      operationId: tempusGetManagedScheduleEmployees
      description: |
        Returns the people who may be booked into this schedule's slots: its scope resolved for you, whether that scope is whole companies, several departments, or a hand-picked list. Use it to populate the assignment dropdown on the slot create and edit forms. Booking anybody outside this list is refused with a 422.

        Only employees holding a contract that is active today are listed, whatever the scope type — a hand-picked selection does not override the contract, so somebody who has left or has not started yet is left out.

        Reading only requires a token belonging to the PBX, like the other schedule GET endpoints. The same list is embedded as `employees` on every schedule payload, so a client that already loaded the schedule does not need this call.

        This replaces the former approach of calling `GET /{pbx_id}/users?filter[group_id]=<the schedule's group>`, which only ever worked for single-department schedules and under-reports for company and employee scoped ones.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'The employees the schedule may assign, ordered by name.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TempusScheduleEmployee'
              example:
                data:
                  -
                    id: 550e8400-e29b-41d4-a716-446655440010
                    fullName: 'Jane Smith'
                    departmentId: 550e8400-e29b-41d4-a716-446655440002
                    departmentName: 'Customer Support'
                  -
                    id: 550e8400-e29b-41d4-a716-446655440011
                    fullName: 'John Baker'
                    departmentId: null
                    departmentName: null
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/schedule-management/{schedule}/calendar':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'Get the weekly calendar for a schedule (user)'
      operationId: tempusGetScheduleCalendar
      description: |
        Returns a weekly calendar view for the schedule, expanding its recurring slots and booked entries across a single week. The week begins on the Monday of the week containing `week_start`; when omitted it defaults to the current week. The schedule must belong to a department the authenticated user is allowed to manage.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: week_start
          in: query
          required: false
          description: 'ISO date used to select the week to render.'
          schema:
            type: string
            format: date
          example: '2026-03-02'
        -
          name: employee_id
          in: query
          required: false
          description: 'Optional employee UUID to restrict the calendar to a single employee.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
      responses:
        200:
          description: 'Weekly calendar for the schedule.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusScheduleCalendar'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management/{schedule}/colors':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    get:
      tags:
        - TempusSchedules
      summary: 'List employee colors for a schedule (user)'
      operationId: tempusListScheduleColors
      description: |
        Returns the per-employee hex colors configured for a schedule. These colors are used to tint each employee's entries on the calendar grid. The schedule must belong to a department the authenticated user is allowed to manage.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      responses:
        200:
          description: 'List of employee colors for the schedule.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        employeeId:
                          type: string
                          format: uuid
                          description: 'Identifier of the Tempus employee.'
                          example: 550e8400-e29b-41d4-a716-446655440002
                        employeeName:
                          type:
                            - string
                            - 'null'
                          description: 'Full name of the employee, or null when unresolved.'
                          example: 'Jane Smith'
                        colorHex:
                          type: string
                          description: 'Hex color assigned to the employee within this schedule.'
                          example: '#4F46E5'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/schedule-management/{schedule}/colors/{employee}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    put:
      tags:
        - TempusSchedules
      summary: 'Set an employee color for a schedule (user)'
      operationId: tempusSetScheduleColor
      description: |
        Creates or updates the hex color assigned to an employee within a schedule. The schedule must belong to a department the authenticated user manages, and the employee must be within the caller's schedules-management scope.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: employee
          in: path
          required: true
          description: 'UUID of the Tempus employee.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440002
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - color_hex
              properties:
                color_hex:
                  type: string
                  pattern: '^#[0-9A-Fa-f]{6}$'
                  description: 'Six-digit hex color string, including the leading hash.'
                  example: '#4F46E5'
      responses:
        200:
          description: 'The color was created or updated.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Color updated.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant or the employee is not within the caller's schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management/{schedule}/slots':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusSchedules
      summary: 'Create a slot in a schedule (user)'
      operationId: tempusCreateScheduleSlot
      description: |
        Creates a recurring time slot within a schedule. The slot's start and end times must fall within the schedule's daily bounds, and the column index is assigned automatically when not supplied. The schedule must belong to a department the authenticated user is allowed to manage.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - start_time
                - end_time
                - recurrence_type
                - recurrence_start_date
              properties:
                column_index:
                  type: integer
                  minimum: 0
                  maximum: 99
                  description: 'Optional column index. Assigned automatically when omitted.'
                  example: 0
                start_time:
                  type: string
                  description: 'Slot start time as `HH:MM`. Must be within the schedule bounds.'
                  example: '09:00'
                end_time:
                  type: string
                  description: 'Slot end time as `HH:MM`. Must be after start_time and within bounds.'
                  example: '17:00'
                recurrence_type:
                  type: string
                  enum:
                    - none
                    - daily
                    - weekly
                    - custom
                  description: 'Recurrence rule for the slot.'
                  example: weekly
                recurrence_days:
                  type: array
                  description: |
                    Weekday numbers the slot recurs on. Required when recurrence_type is weekly or custom.
                  items:
                    type: integer
                    minimum: 1
                    maximum: 7
                    description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                  example:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                recurrence_start_date:
                  type: string
                  format: date
                  description: 'First date the recurrence applies. Must be today or later.'
                  example: '2026-03-02'
                recurrence_end_date:
                  type:
                    - string
                    - 'null'
                  format: date
                  description: 'Last date the recurrence applies. Must be on or after the start date.'
                  example: '2026-12-31'
                recurrence_count:
                  type:
                    - integer
                    - 'null'
                  minimum: 1
                  maximum: 730
                  description: 'Optional number of occurrences.'
                  example: 60
      responses:
        201:
          description: 'The slot was created.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusScheduleSlot'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management/{schedule}/slots/{slot}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    put:
      tags:
        - TempusSchedules
      summary: 'Update a schedule slot (user)'
      operationId: tempusUpdateScheduleSlot
      description: |
        Updates an existing slot. Any subset of the slot fields may be supplied. Start and end times, when provided, must remain within the schedule's daily bounds. The schedule must belong to a department the authenticated user manages, and the slot must belong to that schedule.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: slot
          in: path
          required: true
          description: 'UUID of the slot.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                column_index:
                  type: integer
                  minimum: 0
                  maximum: 99
                  example: 0
                start_time:
                  type: string
                  description: 'Slot start time as `HH:MM`. Must be within the schedule bounds.'
                  example: '09:00'
                end_time:
                  type: string
                  description: 'Slot end time as `HH:MM`. Must be after start_time and within bounds.'
                  example: '17:00'
                recurrence_type:
                  type: string
                  enum:
                    - none
                    - daily
                    - weekly
                    - custom
                  example: weekly
                recurrence_days:
                  type: array
                  description: 'Required when recurrence_type is weekly or custom.'
                  items:
                    type: integer
                    minimum: 1
                    maximum: 7
                    description: 'ISO weekday number (1 = Monday through 7 = Sunday).'
                  example:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                recurrence_start_date:
                  type: string
                  format: date
                  description: 'Must be today or later.'
                  example: '2026-03-02'
                recurrence_end_date:
                  type:
                    - string
                    - 'null'
                  format: date
                  example: '2026-12-31'
                recurrence_count:
                  type:
                    - integer
                    - 'null'
                  minimum: 1
                  maximum: 730
                  example: 60
                is_active:
                  type: boolean
                  example: true
      responses:
        200:
          description: 'The slot was updated.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusScheduleSlot'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
    delete:
      tags:
        - TempusSchedules
      summary: 'Delete a schedule slot (user)'
      operationId: tempusDeleteScheduleSlot
      description: |
        Deletes a slot and all of its entries. The schedule must belong to a department the authenticated user manages, and the slot must belong to that schedule.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: schedule
          in: path
          required: true
          description: 'UUID of the schedule.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440001
        -
          name: slot
          in: path
          required: true
          description: 'UUID of the slot.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
      responses:
        204:
          description: 'The slot and its entries were deleted.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/schedule-management/slots/{slot}/entries':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusSchedules
      summary: 'Create an entry in a slot (user)'
      operationId: tempusCreateScheduleEntry
      description: |
        Books an employee into a slot for a given time window. When `apply_to_all` is true the booking is applied across all occurrences of the recurring slot and a collection of entries is returned, optionally with a `warning` describing skipped occurrences; otherwise a single entry is returned. The employee must be within the caller's schedules-management scope, and the slot must belong to a schedule in a department the caller manages.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: slot
          in: path
          required: true
          description: 'UUID of the slot.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - employee_id
                - start_datetime
                - end_datetime
              properties:
                employee_id:
                  type: string
                  format: uuid
                  description: 'UUID of the Tempus employee to assign.'
                  example: 550e8400-e29b-41d4-a716-446655440002
                start_datetime:
                  type: string
                  format: date-time
                  description: 'Entry start datetime, interpreted in the application timezone.'
                  example: '2026-03-02T09:00:00'
                end_datetime:
                  type: string
                  format: date-time
                  description: 'Entry end datetime. Must be after start_datetime.'
                  example: '2026-03-02T17:00:00'
                apply_to_all:
                  type: boolean
                  description: 'Apply the booking to all occurrences of the recurring slot.'
                  example: false
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free-form note attached to the booking.'
                  example: 'Covering the morning desk'
      responses:
        201:
          description: |
            The entry was created. Returns a single entry when apply_to_all is false, or a collection (optionally with a warning) when apply_to_all is true.
          content:
            application/json:
              schema:
                oneOf:
                  -
                    type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/TempusScheduleEntry'
                  -
                    type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/TempusScheduleEntry'
                      warning:
                        type: string
                        description: 'Summary of occurrences that were skipped.'
                        example: '2 occurrences were skipped due to conflicts.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, or the employee is not within the caller's schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: |
            Validation failed, or the employee is not part of the schedule. A schedule covers a set of companies, departments or hand-picked people, and only those may be booked into its slots: assigning anybody else returns `{"message": "This employee is not part of the schedule. Pick one of the schedule's employees."}`. Take the assignable list from the schedule's `employees` field or from `GET /{pbx_id}/schedule-management/{schedule}/employees`.
  '/{pbx_id}/schedule-management/slots/{slot}/auto-assign':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    post:
      tags:
        - TempusSchedules
      summary: 'Auto-assign the best employee to a slot (user)'
      operationId: tempusAutoAssignScheduleEntry
      description: |
        Selects the most eligible employee for a slot over the given time window and books them into it, returning the created entry. The chosen employee must be within the caller's schedules-management scope; if no eligible in-scope employee is found a 404 is returned. The slot must belong to a schedule in a department the caller manages.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: slot
          in: path
          required: true
          description: 'UUID of the slot.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440003
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - start_datetime
                - end_datetime
              properties:
                start_datetime:
                  type: string
                  format: date-time
                  description: 'Entry start datetime, interpreted in the application timezone.'
                  example: '2026-03-02T09:00:00'
                end_datetime:
                  type: string
                  format: date-time
                  description: 'Entry end datetime. Must be after start_datetime.'
                  example: '2026-03-02T17:00:00'
      responses:
        201:
          description: 'The entry was created for the auto-selected employee.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TempusScheduleEntry'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: |
            The slot was not found within the caller's scope, or no eligible in-scope employee could be assigned.
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/{pbx_id}/schedule-management/entries/{entry}':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    put:
      tags:
        - TempusSchedules
      summary: 'Update a schedule entry (user)'
      operationId: tempusUpdateScheduleEntry
      description: |
        Updates an existing entry. Any subset of the entry fields may be supplied. When `apply_to_all` is true the change is propagated across the recurring series and a collection is returned; otherwise a single entry is returned. When changing the employee, the new employee must be within the caller's schedules-management scope. The entry must belong to a schedule in a department the caller manages.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: entry
          in: path
          required: true
          description: 'UUID of the entry.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440004
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                employee_id:
                  type: string
                  format: uuid
                  description: 'UUID of the Tempus employee to assign.'
                  example: 550e8400-e29b-41d4-a716-446655440002
                start_datetime:
                  type: string
                  format: date-time
                  description: 'Entry start datetime, interpreted in the application timezone.'
                  example: '2026-03-02T09:00:00'
                end_datetime:
                  type: string
                  format: date-time
                  description: 'Entry end datetime. Must be after start_datetime.'
                  example: '2026-03-02T17:00:00'
                apply_to_all:
                  type: boolean
                  description: 'Propagate the change across the recurring series.'
                  example: false
                comment:
                  type:
                    - string
                    - 'null'
                  maxLength: 1000
                  description: 'Optional free-form note attached to the booking.'
                  example: 'Covering the morning desk'
      responses:
        200:
          description: |
            The entry was updated. Returns a single entry when apply_to_all is false, or a collection when apply_to_all is true.
          content:
            application/json:
              schema:
                oneOf:
                  -
                    type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/TempusScheduleEntry'
                  -
                    type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/TempusScheduleEntry'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, or the target employee is not within the caller's schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: |
            Validation failed, or the employee is not part of the schedule. A schedule covers a set of companies, departments or hand-picked people, and only those may be booked into its slots: assigning anybody else returns `{"message": "This employee is not part of the schedule. Pick one of the schedule's employees."}`. Take the assignable list from the schedule's `employees` field or from `GET /{pbx_id}/schedule-management/{schedule}/employees`.
    delete:
      tags:
        - TempusSchedules
      summary: 'Delete a schedule entry (user)'
      operationId: tempusDeleteScheduleEntry
      description: |
        Deletes an entry. When `apply_to_all` is true the entire recurring series is removed; otherwise only the single occurrence is deleted. The entry must belong to a schedule in a department the caller manages.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: entry
          in: path
          required: true
          description: 'UUID of the entry.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440004
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                apply_to_all:
                  type: boolean
                  description: 'Delete the entire recurring series rather than one occurrence.'
                  example: false
      responses:
        204:
          description: 'The entry was deleted.'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
  '/{pbx_id}/schedule-management/entries/{entry}/move':
    servers:
      -
        url: 'https://cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus production API v1 server'
      -
        url: 'https://staging-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus staging API v1 server'
      -
        url: 'https://dev-cockpit.voxbi.com/tempus/api/v1'
        description: 'Tempus dev API v1 server'
    patch:
      tags:
        - TempusSchedules
      summary: 'Move a schedule entry to a new time (user)'
      operationId: tempusMoveScheduleEntry
      description: |
        Reschedules an entry to a new start and end datetime. The move is rejected with 422 when the new window overlaps another booking for the same employee in the same department. When `apply_to_all` is false the moved occurrence is marked as an exception and a single entry is returned; when true the change is propagated across the recurring series and a collection is returned. The entry must belong to a schedule in a department the caller manages.
      security:
        -
          bearerAuth: {}
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: pbx_id
          in: path
          required: true
          description: 'UUID of the PBX tenant.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        -
          name: entry
          in: path
          required: true
          description: 'UUID of the entry.'
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440004
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - start_datetime
                - end_datetime
              properties:
                start_datetime:
                  type: string
                  format: date-time
                  description: 'New entry start datetime, interpreted in the application timezone.'
                  example: '2026-03-03T09:00:00'
                end_datetime:
                  type: string
                  format: date-time
                  description: 'New entry end datetime. Must be after start_datetime.'
                  example: '2026-03-03T17:00:00'
                apply_to_all:
                  type: boolean
                  description: 'Propagate the move across the recurring series.'
                  example: false
      responses:
        200:
          description: |
            The entry was moved. Returns a single entry when apply_to_all is false, or a collection when apply_to_all is true.
          content:
            application/json:
              schema:
                oneOf:
                  -
                    type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/TempusScheduleEntry'
                  -
                    type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/TempusScheduleEntry'
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: |
            The authenticated user is outside the requested tenant, has no associated employee record, or has an empty schedules-management scope.
        404:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
        422:
          description: 'Unprocessable Parameters. This error is returned when a parameter is not valid.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      filter:
                        type: array
                        items:
                          type: string
                      sort:
                        type: array
                        items:
                          type: string
                      page:
                        type: array
                        items:
                          type: string
                      per_page:
                        type: array
                        items:
                          type: string
              example:
                errors:
                  filter:
                    - 'The filter field must be an array.'
                  sort:
                    - 'The sort field must be a string.'
                  page:
                    - 'The page field must be an integer.'
                  per_page:
                    - 'The per page field must be an integer.'
  '/call-flow-steps/{id}':
    get:
      tags:
        - CallFlowSteps
      summary: 'Get a Call flow step'
      operationId: getCallFlowStep
      description: |
        Returns the call flow step identified by the path parameter. Multi-tenant scoping is
        enforced: the caller can only fetch resources within their own PBX.
      parameters:
        -
          name: accept
          in: header
          schema:
            type: string
            example: application/json
        -
          name: id
          in: path
          schema:
            type: string
            format: uuid
          required: true
      responses:
        5XX:
          description: |
            Server error. An unexpected condition was encountered on the server and the
            request could not be completed. The body is a generic JSON envelope with a
            `message` field. The response is logged on the server side; quote the
            request URL + timestamp when reporting an issue.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  exception:
                    type: string
                    description: 'Only present in non-production environments.'
                  file:
                    type: string
                    description: 'Only present in non-production environments.'
                  line:
                    type: integer
                    description: 'Only present in non-production environments.'
              example:
                message: 'Server Error'
        200:
          description: OK
          headers:
            Host:
              schema:
                type: string
                example: cockpit.voxbi.com
            Date:
              schema:
                type: string
                example: 'Mon, 16 Oct 2023 14:08:48 GMT'
            Connection:
              schema:
                type: string
                example: close
            Cache-Control:
              schema:
                type: string
                example: 'no-cache, private'
            Content-Type:
              schema:
                type: string
                example: application/json
            X-RateLimit-Limit:
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              schema:
                type: integer
                example: 59
            Vary:
              schema:
                type: string
                example: Origin
          content:
            application/json:
              schema:
                description: |
                  A single step inside a call flow. Steps are evaluated in ascending `order`
                  to drive how an inbound call is handled. The `type` field discriminates the
                  shape of `options`: each variant below documents the keys carried in
                  `options` for that particular step type. Variants with no configurable
                  settings (`hang_up`, `start_recording`, `answer`) use an empty options
                  object. The v1 API returns exactly these top-level fields on every variant:
                  `id`, `pbx_id`, `call_flow_id`, `type`, `options`, `is_active`, `order`.
                  Most ID references inside `options` are UUIDs of related resources (users,
                  groups, IVRs, queues, schedules, etc.) scoped to the same tenant.
                oneOf:
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (ring_user)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - ring_user
                        description: 'Step type. For this variant it rings one or more cockpit users, SIP devices, or groups.'
                        example: ring_user
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings describing which targets to ring and for how long.'
                        required:
                          - duration
                        properties:
                          duration:
                            type: integer
                            format: int32
                            minimum: 1
                            description: 'Ring duration in seconds before moving to the next step.'
                            example: 20
                          also_ring_dialed_extension:
                            type: boolean
                            description: 'When true, also rings the extension that was originally dialed.'
                            example: false
                          also_ring_everyone_in_the_user_group:
                            type: boolean
                            description: "When true, also rings every member of the dialed user's group."
                            example: false
                          dial_mobile_twinnings:
                            type: boolean
                            description: 'When true, also rings the mobile twinning numbers configured for the targets.'
                            example: false
                          missed_calls:
                            type: boolean
                            description: 'When true, an unanswered call on this step counts as a missed call for the targets. Defaults to true.'
                            example: true
                          music_on_hold:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the music-on-hold playlist played while ringing.'
                            example: 550e8400-e29b-41d4-a716-446655440010
                          users:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of the users to ring.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440011
                          sip_devices:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of the SIP devices to ring.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440012
                          groups:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of the user groups to ring.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440013
                          tags:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of tags whose tagged users should be rung.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440014
                          locations:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of locations whose users should be rung.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440015
                          languages:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of languages used to select which users to ring.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440016
                          pools:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of pools whose users should be rung.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440017
                          statuses:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of Tempus statuses used to filter which users are rung.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440018
                          pickup_lines:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of users whose calls may be picked up by this step.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440019
                          sub_statuses:
                            type:
                              - object
                              - 'null'
                            description: |
                              Map keyed by Tempus status UUID. Each value is the list of
                              Tempus sub-status UUIDs selected under that status.
                            additionalProperties:
                              type: array
                              items:
                                type: string
                                format: uuid
                            example:
                              550e8400-e29b-41d4-a716-446655440018:
                                - 550e8400-e29b-41d4-a716-446655440020
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (ring_external_number)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - ring_external_number
                        description: 'Step type. For this variant it dials out to an external PSTN number.'
                        example: ring_external_number
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 1
                      options:
                        type: object
                        description: 'Settings describing the external number to dial.'
                        properties:
                          duration:
                            type: integer
                            format: int32
                            minimum: 1
                            description: 'Ring duration in seconds before moving to the next step.'
                            example: 30
                          number:
                            type:
                              - string
                              - 'null'
                            description: 'External destination number in E.164 format.'
                            example: '+12125550100'
                          music_on_hold:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the music-on-hold playlist played while ringing.'
                            example: 550e8400-e29b-41d4-a716-446655440010
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (call_flow)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - call_flow
                        description: 'Step type. For this variant it routes the call to another call flow or extension.'
                        example: call_flow
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 2
                      options:
                        type: object
                        description: 'Settings describing the destination and optional schedule.'
                        required:
                          - call_flow_or_extension
                        properties:
                          call_flow_or_extension:
                            type: string
                            enum:
                              - extension
                              - call_flow
                            description: 'Selects whether the call is routed to an extension or another call flow.'
                            example: call_flow
                          extension:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the destination extension (used when routing to an extension).'
                            example: 550e8400-e29b-41d4-a716-446655440030
                          call_flow:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the destination call flow (used when routing to a call flow).'
                            example: 550e8400-e29b-41d4-a716-446655440031
                          schedule:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of a schedule that gates when this routing applies.'
                            example: 550e8400-e29b-41d4-a716-446655440032
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (go_to_ivr)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - go_to_ivr
                        description: 'Step type. For this variant it hands the call off to an IVR menu.'
                        example: go_to_ivr
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings identifying which IVR to enter.'
                        properties:
                          ivr:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the IVR menu to enter.'
                            example: 550e8400-e29b-41d4-a716-446655440040
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (enter_queue)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - enter_queue
                        description: 'Step type. For this variant it parks the caller in a queue.'
                        example: enter_queue
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 1
                      options:
                        type: object
                        description: 'Settings identifying the queue and how long to wait.'
                        properties:
                          duration:
                            type: integer
                            format: int32
                            minimum: 1
                            description: 'Maximum time in seconds to keep the caller queued before moving on.'
                            example: 60
                          queue:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the queue to enter.'
                            example: 550e8400-e29b-41d4-a716-446655440050
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (text_to_speech)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - text_to_speech
                        description: 'Step type. For this variant it plays an announcement (sound file or synthesized speech).'
                        example: text_to_speech
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings describing the announcement source.'
                        required:
                          - announcement_type
                        properties:
                          announcement_type:
                            type: string
                            enum:
                              - sound_file
                              - tts_tag
                              - tts_message
                            description: 'Selects the announcement source (a stored sound file, a TTS tag, or a free-text TTS message).'
                            example: tts_message
                          sound_file:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the announcement sound file to play (used when announcement_type is sound_file).'
                            example: 550e8400-e29b-41d4-a716-446655440060
                          language:
                            type:
                              - string
                              - 'null'
                            description: |
                              Announcement language override. `null` (Auto) plays the variant for the
                              language detected/inherited earlier in the call; otherwise an ISO-639-1 code
                              forces that variant.
                            enum:
                              - en
                              - de
                              - fr
                              - lb
                              - es
                              - it
                              - pt
                              - nl
                              - pl
                              - ru
                              - tr
                              - sv
                              - da
                              - 'no'
                              - fi
                              - cs
                              - sk
                              - el
                              - hu
                              - ro
                              - bg
                              - hr
                              - uk
                              - ar
                              - he
                              - hi
                              - ja
                              - ko
                              - zh
                              - id
                              - ms
                              - th
                              - vi
                              - null
                            example: fr
                          tts_tag:
                            type:
                              - string
                              - 'null'
                            description: 'Predefined TTS tag identifying a templated message (used when announcement_type is tts_tag).'
                            example: greeting_morning
                          tts_message:
                            type:
                              - string
                              - 'null'
                            description: 'Free-text message to synthesize and play (used when announcement_type is tts_message).'
                            example: 'Welcome to Customer Support.'
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (change_ringtone_and_label)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - change_ringtone_and_label
                        description: 'Step type. For this variant it overrides the ringtone and the caller display label.'
                        example: change_ringtone_and_label
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings overriding ringtone, label, and music on hold.'
                        properties:
                          ringtone:
                            type:
                              - string
                              - 'null'
                            enum:
                              - alert-ring1
                              - alert-ring2
                              - alert-ring3
                              - alert-ring4
                              - alert-ring5
                              - 'null'
                            description: 'Ringtone key to apply on the receiving device.'
                            example: alert-ring1
                          label:
                            type:
                              - string
                              - 'null'
                            description: 'Display label shown to the called party for the incoming call.'
                            example: VIP
                          music_on_hold:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the music-on-hold playlist to apply.'
                            example: 550e8400-e29b-41d4-a716-446655440010
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (webhook)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - webhook
                        description: 'Step type. For this variant it fires an outbound HTTP request mid-flow.'
                        example: webhook
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 2
                      options:
                        type: object
                        description: 'Settings describing the HTTP endpoint to call.'
                        properties:
                          url:
                            type:
                              - string
                              - 'null'
                            format: uri
                            description: 'HTTP(S) endpoint invoked when the step runs.'
                            example: 'https://cockpit.voxbi.com/hooks/call'
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (send_to_email)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - send_to_email
                        description: 'Step type. For this variant it emails a recording/voicemail to recipients.'
                        example: send_to_email
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 3
                      options:
                        type: object
                        description: 'Settings describing the recording to attach and the recipients.'
                        properties:
                          sound_file:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the sound file (recording) to attach to the email.'
                            example: 550e8400-e29b-41d4-a716-446655440060
                          language:
                            type:
                              - string
                              - 'null'
                            description: 'Announcement language override; `null` (Auto) keeps the detected/inherited language.'
                            enum:
                              - en
                              - de
                              - fr
                              - lb
                              - es
                              - it
                              - pt
                              - nl
                              - pl
                              - ru
                              - tr
                              - sv
                              - da
                              - 'no'
                              - fi
                              - cs
                              - sk
                              - el
                              - hu
                              - ro
                              - bg
                              - hr
                              - uk
                              - ar
                              - he
                              - hi
                              - ja
                              - ko
                              - zh
                              - id
                              - ms
                              - th
                              - vi
                              - null
                            example: fr
                          email:
                            type:
                              - string
                              - 'null'
                            format: email
                            description: 'Explicit recipient email address.'
                            example: support@example.com
                          email_user:
                            type:
                              - array
                              - 'null'
                            description: 'Identifiers of users whose email addresses should receive the message.'
                            items:
                              type: string
                              format: uuid
                            example:
                              - 550e8400-e29b-41d4-a716-446655440011
                          email_to_called_user:
                            type: boolean
                            description: 'When true, also emails the user who was originally called.'
                            example: false
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (conference_room)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - conference_room
                        description: 'Step type. For this variant it drops the caller into a conference room.'
                        example: conference_room
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings identifying the conference room extension.'
                        properties:
                          extension:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the extension hosting the conference room.'
                            example: 550e8400-e29b-41d4-a716-446655440030
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (ivr_extension)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - ivr_extension
                        description: 'Step type. For this variant it plays a sound and waits for IVR-style key input.'
                        example: ivr_extension
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings identifying the sound file to play.'
                        properties:
                          sound_file:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the sound file to play before collecting input.'
                            example: 550e8400-e29b-41d4-a716-446655440060
                          language:
                            type:
                              - string
                              - 'null'
                            description: 'Announcement language override; `null` (Auto) keeps the detected/inherited language.'
                            enum:
                              - en
                              - de
                              - fr
                              - lb
                              - es
                              - it
                              - pt
                              - nl
                              - pl
                              - ru
                              - tr
                              - sv
                              - da
                              - 'no'
                              - fi
                              - cs
                              - sk
                              - el
                              - hu
                              - ro
                              - bg
                              - hr
                              - uk
                              - ar
                              - he
                              - hi
                              - ja
                              - ko
                              - zh
                              - id
                              - ms
                              - th
                              - vi
                              - null
                            example: fr
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (multicast)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - multicast
                        description: 'Step type. For this variant it pages a multicast (intercom) group.'
                        example: multicast
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings identifying the multicast group and access PIN.'
                        properties:
                          multicast_group:
                            type:
                              - string
                              - 'null'
                            description: 'Name or identifier of the multicast paging group.'
                            example: paging-floor-1
                          multicast_pin:
                            type:
                              - string
                              - 'null'
                            description: 'PIN required to join the multicast group.'
                            example: '1234'
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (ai_assistant)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - ai_assistant
                        description: 'Step type. For this variant it hands the call off to a Smart IVR / AI agent.'
                        example: ai_assistant
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        description: 'Settings identifying the AI provider and agent.'
                        properties:
                          ai_provider:
                            type: string
                            enum:
                              - famulor
                            description: 'AI provider backing the assistant.'
                            example: famulor
                          famulor_agent:
                            type:
                              - string
                              - 'null'
                            format: uuid
                            description: 'Identifier of the Famulor agent that handles the call.'
                            example: 550e8400-e29b-41d4-a716-446655440070
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (hang_up)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - hang_up
                        description: 'Step type. For this variant it terminates the call. This step has no configurable options.'
                        example: hang_up
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 4
                      options:
                        type: object
                        additionalProperties: false
                        description: 'Empty options object (this step type has no settings).'
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (start_recording)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - start_recording
                        description: 'Step type. For this variant it begins call recording. This step has no configurable options.'
                        example: start_recording
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        additionalProperties: false
                        description: 'Empty options object (this step type has no settings).'
                  -
                    type: object
                    required:
                      - id
                      - pbx_id
                      - call_flow_id
                      - type
                      - options
                      - is_active
                      - order
                    title: 'CallFlowStep (answer)'
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: 'Unique identifier of the call flow step'
                        example: 550e8400-e29b-41d4-a716-446655440000
                        readOnly: true
                      pbx_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the PBX (tenant) this step belongs to'
                        example: 550e8400-e29b-41d4-a716-446655440001
                      call_flow_id:
                        type: string
                        format: uuid
                        description: 'Identifier of the parent call flow that owns this step'
                        example: 550e8400-e29b-41d4-a716-446655440002
                      type:
                        type: string
                        enum:
                          - answer
                        description: 'Step type. For this variant it explicitly answers the call. This step has no configurable options.'
                        example: answer
                      is_active:
                        type: boolean
                        description: 'Whether the step is enabled. Disabled steps are skipped during call routing.'
                        example: true
                      order:
                        type: integer
                        format: int32
                        minimum: 0
                        description: 'Zero-based position of the step within its call flow. Steps run in ascending order.'
                        example: 0
                      options:
                        type: object
                        additionalProperties: false
                        description: 'Empty options object (this step type has no settings).'
                discriminator:
                  propertyName: type
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                pbx_id: 550e8400-e29b-41d4-a716-446655440001
                call_flow_id: 550e8400-e29b-41d4-a716-446655440002
                type: ring_user
                options:
                  duration: 20
                  also_ring_dialed_extension: false
                  also_ring_everyone_in_the_user_group: false
                  dial_mobile_twinnings: false
                  missed_calls: true
                  music_on_hold: 550e8400-e29b-41d4-a716-446655440000
                  users:
                    - 550e8400-e29b-41d4-a716-446655440000
                  sip_devices:
                    - 550e8400-e29b-41d4-a716-446655440000
                  groups:
                    - 550e8400-e29b-41d4-a716-446655440000
                  tags:
                    - 550e8400-e29b-41d4-a716-446655440000
                  locations:
                    - 550e8400-e29b-41d4-a716-446655440000
                  languages:
                    - 550e8400-e29b-41d4-a716-446655440000
                  pools:
                    - 550e8400-e29b-41d4-a716-446655440000
                  statuses:
                    - 550e8400-e29b-41d4-a716-446655440000
                  pickup_lines:
                    - 550e8400-e29b-41d4-a716-446655440000
        401:
          description: 'Authorization Token Missing. This error is returned when the authorization token is missing.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Authorization Token is missing'
                    description: 'Error message'
              example:
                error: 'Authorization Token is missing'
        403:
          description: 'Data Not Found. This error is returned when the requested data is not found.'
          headers:
            Cache-Control:
              schema:
                type: string
                example: 'private, must-revalidate'
            Connection:
              schema:
                type: string
                example: keep-alive
            Content-Type:
              schema:
                type: string
                example: application/json
            Vary:
              schema:
                type: string
                example: Origin
            X-RateLimit-Limit:
              description: 'Max requests allowed in the current rate-limit window.'
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: 'Requests remaining in the current rate-limit window.'
              schema:
                type: integer
                example: 57
          content:
            application/json:
              schema:
                type: object
                description: 'Data not found'
                properties:
                  message:
                    type: array
                    items:
                      type: string
              example:
                message:
                  - 'Data not found'
