openapi: 3.1.0
info:
  title: Moss public API
  version: 1.29.1
  license:
    name: Proprietary
    url: https://getmoss.com/public/terms-and-conditions/20260206_INT-en_Nufin_GmbH_Moss_API_Terms_And_Conditions_v1.0.pdf
  description: |
    Public API for getmoss.com services

    ## Authentication

    This API uses OAuth 2.0 client credentials flow to obtain Bearer tokens for authentication.

    ### Getting Started

    1. **Create API Keys**: Only admins can create API keys. Go to Settings → Platform → API Keys
    2. **Obtain Access Token**: Use your Key ID and Secret Key to request a Bearer token
    3. **Use Bearer Token**: Include the token in API requests via Authorization header

    ### OAuth 2.0 Token Request

    **Endpoint:** `POST {server_url}/oauth2/token`

    **Request Examples:**

    *Staging:*
    ```bash
    curl -v -X POST "https://public-api.runmoss.run/oauth2/token" \
         -H "content-type: application/x-www-form-urlencoded" \
         -d 'grant_type=client_credentials&client_id=kid_FaYnufhSMSP1qaXy&client_secret=sk_rKvWDzU6h46hiy3tluqskkrX6pepQTXI'
    ```

    *Production (when available):*
    ```bash
    curl -v -X POST "https://public-api.getmoss.com/oauth2/token" \
         -H "content-type: application/x-www-form-urlencoded" \
         -d 'grant_type=client_credentials&client_id=kid_FaYnufhSMSP1qaXy&client_secret=sk_rKvWDzU6h46hiy3tluqskkrX6pepQTXI'
    ```

    **Request Parameters:**
    - `grant_type`: Must be `client_credentials`
    - `client_id`: Your Key ID (starts with `kid_`)
    - `client_secret`: Your Secret Key (starts with `sk_`)

    **Response Example:**
    ```json
    {
      "access_token": "eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiI4MzliZWNlNS0xOTA2LTRmMzctOWIyOC1hNjFmMTU0NWY3ODEiLCJpYXQiOjE3NjgyMjg2NzAsImV4cCI6MTc2ODIzMjI3MCwidHlwIjoiYXQrand0Iiwic3JjIjoiUFVCX0FQSV9DTElFTlQiLCJjbGllbnRfaWQiOiJraWRfZkVLbXJtZ0N0TTkxYWxweSIsInNjb3BlIjoicmVhZCIsImlzcyI6Imh0dHBzOi8vcHVibGljLWFwaS5ydW5tb3NzLnJ1biIsImF1ZCI6WyJodHRwczovL3B1YmxpYy1hcGkucnVubW9zcy5ydW4iXSwianRpIjoiN2E0NGNiYzgtMzE2OS00YWQ0LWE1ZGYtN2M0MGEwYjNkMWZhIiwibmJmIjoxNzY4MjI4NjcwLCJyb2wiOlsiUFVCX0FQSSJdfQ.UM2yAVhFQsjKfAnAbrBDBtBicIe5ph2_kqLP9-iFjiCCgn9s2g30EhPpL-LgVcI3xY3u33igcl_RKe1FXxnR1w",
      "token_type": "Bearer",
      "expires_in": 3600,
      "scope": "read"
    }
    ```

    ### Using Access Tokens

    Include the `access_token` value in the Authorization header of your API requests:
    ```
    Authorization: Bearer <ACCESS_TOKEN>
    ```

    **Example API Requests:**

    *Staging:*
    ```bash
    # Wall of shame endpoint - COMMENTED OUT FOR FUTURE USE
    # curl -H "Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiI4MzliZWNlNS0xOTA2LTRmMzctOWIyOC1hNjFmMTU0NWY3ODEiLCJpYXQiOjE3NjgyMjg2NzAsImV4cCI6MTc2ODIzMjI3MCwidHlwIjoiYXQrand0Iiwic3JjIjoiUFVCX0FQSV9DTElFTlQiLCJjbGllbnRfaWQiOiJraWRfZkVLbXJtZ0N0TTkxYWxweSIsInNjb3BlIjoicmVhZCIsImlzcyI6Imh0dHBzOi8vcHVibGljLWFwaS5ydW5tb3NzLnJ1biIsImF1ZCI6WyJodHRwczovL3B1YmxpYy1hcGkucnVubW9zcy5ydW4iXSwianRpIjoiN2E0NGNiYzgtMzE2OS00YWQ0LWE1ZGYtN2M0MGEwYjNkMWZhIiwibmJmIjoxNzY4MjI4NjcwLCJyb2wiOlsiUFVCX0FQSSJdfQ.UM2yAVhFQsjKfAnAbrBDBtBicIe5ph2_kqLP9-iFjiCCgn9s2g30EhPpL-LgVcI3xY3u33igcl_RKe1FXxnR1w" \
    #      https://public-api.runmoss.run/v1/wall-of-shame

    curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
         https://public-api.runmoss.run/v1/expenses
    ```

    *Production (when available):*
    ```bash
    # Wall of shame endpoint - COMMENTED OUT FOR FUTURE USE
    # curl -H "Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiI4MzliZWNlNS0xOTA2LTRmMzctOWIyOC1hNjFmMTU0NWY3ODEiLCJpYXQiOjE3NjgyMjg2NzAsImV4cCI6MTc2ODIzMjI3MCwidHlwIjoiYXQrand0Iiwic3JjIjoiUFVCX0FQSV9DTElFTlQiLCJjbGllbnRfaWQiOiJraWRfZkVLbXJtZ0N0TTkxYWxweSIsInNjb3BlIjoicmVhZCIsImlzcyI6Imh0dHBzOi8vcHVibGljLWFwaS5ydW5tb3NzLnJ1biIsImF1ZCI6WyJodHRwczovL3B1YmxpYy1hcGkucnVubW9zcy5ydW4iXSwianRpIjoiN2E0NGNiYzgtMzE2OS00YWQ0LWE1ZGYtN2M0MGEwYjNkMWZhIiwibmJmIjoxNzY4MjI4NjcwLCJyb2wiOlsiUFVCX0FQSSJdfQ.UM2yAVhFQsjKfAnAbrBDBtBicIe5ph2_kqLP9-iFjiCCgn9s2g30EhPpL-LgVcI3xY3u33igcl_RKe1FXxnR1w" \
    #      https://public-api.getmoss.com/v1/wall-of-shame

    curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
         https://public-api.getmoss.com/v1/expenses
    ```

    ### Token Management

    - **Token Lifetime**: Access tokens expire after 1 hour (3600 seconds)
    - **Token Refresh**: Since this is client credentials flow, request a new token when the current one expires
    - **Token Format**: JWT (JSON Web Token) with embedded user and scope information

    ### Scopes and Permissions

    - **`read`**: Grants access to GET endpoints for retrieving data
    - **`write`**: Grants access to all endpoints including POST, PUT, DELETE operations
    - **Scope Hierarchy**: `write` scope includes `read` permissions

    ### API Key Management

    **Creating API Keys:**
    1. Log in to your Moss account as an admin
    2. Navigate to Settings → Platform → API Keys
    3. Click "Create API Key"
    4. Confirm the operation with Moss mobile app
    5. Save both the Key ID (`kid_*`) and Secret Key (`sk_*`) securely
    6. **Important**: Store credentials securely and never expose them in client-side code

    **Security Best Practices:**
    - Rotate API keys regularly
    - Use environment variables to store credentials
    - Never commit API keys to version control
    - Monitor API key usage for suspicious activity

    ## Rate Limiting

    All API endpoints are subject to rate limiting per organization and OAuth scope.

    ### Response Headers

    Every API response includes the following rate limiting headers:

    | Header | Description |
    |--------|-------------|
    | `X-RateLimit-Limit` | Maximum requests allowed in the current rate limit window |
    | `X-RateLimit-Remaining` | Requests remaining in the current window |
    | `X-RateLimit-Reset` | Unix timestamp (UTC seconds) when the window resets |
    | `X-RateLimit-Scope` | Scope bucket for this limit: `read` (GET) or `write` (POST/PUT/DELETE) |

    ### Rate Limit Exceeded (HTTP 429)

    When the rate limit is exceeded the API returns HTTP **429 Too Many Requests** with:
    - All four `X-RateLimit-*` headers (`X-RateLimit-Remaining` will be `0`)
    - `Retry-After` header with the number of seconds to wait before retrying
    - A JSON error body with `type: ERR_RATE_LIMIT_EXCEEDED`

    ### Best Practices

    - Monitor `X-RateLimit-Remaining` to avoid hitting the limit
    - Implement exponential backoff when receiving 429 responses
    - Respect the `Retry-After` header value when retrying
servers:
  - url: https://public-api.getmoss.com
    description: Production server
  - url: https://public-api.runmoss.run
    description: Staging server
  - url: http://127.0.0.1:8000/public-api
    description: Local development server (kubectl port-forward service/edge 8000:8080)
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Bearer token authentication using OAuth 2.0 client credentials flow.

        **Token Acquisition:**
        1. Create API keys in Settings → Platform → API Keys (admin only)
        2. Request access token: `POST {server_url}/oauth2/token`
        3. Use the `access_token` from response as Bearer token

        **Scopes:**
        - `read`: Access to read-only endpoints (GET operations)
        - `write`: Access to all endpoints (includes read + POST/PUT/DELETE operations)

        **Example:**
        ```
        Authorization: Bearer eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiI4MzliZWNlNS0xOTA2...
        ```
    OAuth2:
      type: oauth2
      description: OAuth 2.0 client credentials flow for obtaining access tokens
      flows:
        clientCredentials:
          tokenUrl: /oauth2/token
          scopes:
            read: Access to read-only endpoints (GET operations)
            write: Access to all endpoints (includes read + POST/PUT/DELETE operations)
  schemas:
    ExpenseType:
      $ref: ./schemas/ExpenseType.yaml
    HeaderExpenseType:
      $ref: ./schemas/HeaderExpenseType.yaml
    ExpenseSubtype:
      $ref: ./schemas/ExpenseSubtype.yaml
    ExpenseStatus:
      $ref: ./schemas/ExpenseStatus.yaml
    ExportStatus:
      $ref: ./schemas/ExportStatus.yaml
    ExportMetadata:
      $ref: ./schemas/ExportMetadata.yaml
    HospitalityExpenseParticipant:
      $ref: ./schemas/HospitalityExpenseParticipant.yaml
    ExpenseDimension:
      $ref: ./schemas/ExpenseDimension.yaml
    ExpenseMetadata:
      type: object
      properties:
        type:
          $ref: '#/components/schemas/ExpenseType'
          description: Type of expense that determines the metadata structure
      discriminator:
        propertyName: type
        mapping:
          CARD_TRANSACTION: '#/components/schemas/CardTransactionMetadata'
          REIMBURSEMENT: '#/components/schemas/ReimbursementMetadata'
          REIMBURSEMENT_INVOICE_LINE: '#/components/schemas/ReimbursementInvoiceLineMetadata'
          REIMBURSEMENT_INVOICE_LINE_SPLIT: '#/components/schemas/ReimbursementInvoiceLineSplitMetadata'
          MILEAGE_LINE: '#/components/schemas/MileageLineMetadata'
          PER_DIEM_LINE: '#/components/schemas/PerDiemLineMetadata'
          INVOICE: '#/components/schemas/InvoiceMetadata'
      oneOf:
        - $ref: '#/components/schemas/CardTransactionMetadata'
        - $ref: '#/components/schemas/ReimbursementMetadata'
        - $ref: '#/components/schemas/ReimbursementInvoiceLineMetadata'
        - $ref: '#/components/schemas/ReimbursementInvoiceLineSplitMetadata'
        - $ref: '#/components/schemas/MileageLineMetadata'
        - $ref: '#/components/schemas/PerDiemLineMetadata'
        - $ref: '#/components/schemas/InvoiceMetadata'
      required:
        - type
      description: |
        Base polymorphic metadata object for expenses and expense lines. The actual metadata structure
        will be determined by the expense type using discriminator-based resolution.
    CardTransactionMetadata:
      $ref: ./schemas/CardTransactionMetadata.yaml
    ReimbursementMetadata:
      $ref: ./schemas/ReimbursementMetadata.yaml
    ReimbursementInvoiceLineMetadata:
      $ref: ./schemas/ReimbursementInvoiceLineMetadata.yaml
    ReimbursementInvoiceLineSplitMetadata:
      $ref: ./schemas/ReimbursementInvoiceLineSplitMetadata.yaml
    MileageLineMetadata:
      $ref: ./schemas/MileageLineMetadata.yaml
    PerDiemLineMetadata:
      $ref: ./schemas/PerDiemLineMetadata.yaml
    InvoiceMetadata:
      $ref: ./schemas/InvoiceMetadata.yaml
    PaymentStatus:
      $ref: ./schemas/PaymentStatus.yaml
    PaymentChannel:
      $ref: ./schemas/PaymentChannel.yaml
    CardTransactionMerchantDetails:
      $ref: ./schemas/CardTransactionMerchantDetails.yaml
    PerDiemLocation:
      $ref: ./schemas/PerDiemLocation.yaml
    PerDiemItineraryItem:
      $ref: ./schemas/PerDiemItineraryItem.yaml
    InvoiceApprovedBy:
      $ref: ./schemas/InvoiceApprovedBy.yaml
    InvoiceRejectedBy:
      $ref: ./schemas/InvoiceRejectedBy.yaml
    InvoiceVerifiedBy:
      $ref: ./schemas/InvoiceVerifiedBy.yaml
    InvoiceLastReviewedBy:
      $ref: ./schemas/InvoiceLastReviewedBy.yaml
    InvoicePaymentTerm:
      $ref: ./schemas/InvoicePaymentTerm.yaml
    InvoicePaymentTermLine:
      $ref: ./schemas/PaymentTermLine.yaml
    PurchaseRequestUsageMetadata:
      $ref: ./schemas/PurchaseRequestUsageMetadata.yaml
    AccountingPeriodStatus:
      $ref: ./schemas/accounting_period/AccountingPeriodStatus.yaml
    AccountingPeriod:
      $ref: ./schemas/accounting_period/AccountingPeriod.yaml
    AccountingPeriodsResponse:
      $ref: ./schemas/accounting_period/AccountingPeriodsResponse.yaml
    CreateAccountingPeriodsRequest:
      $ref: ./schemas/accounting_period/CreateAccountingPeriodsRequest.yaml
    UpdateAccountingPeriodRequest:
      $ref: ./schemas/accounting_period/UpdateAccountingPeriodRequest.yaml
    UpdateAccountingPeriodsStatusRequest:
      $ref: ./schemas/accounting_period/UpdateAccountingPeriodsStatusRequest.yaml
    DeleteAccountingPeriodsRequest:
      $ref: ./schemas/accounting_period/DeleteAccountingPeriodsRequest.yaml
    CustomerOperation:
      $ref: ./schemas/accounting_view_preferences/CustomerOperation.yaml
    CustomerViewPreferences:
      $ref: ./schemas/accounting_view_preferences/CustomerViewPreferences.yaml
    AccountingViewPreferencesResponse:
      $ref: ./schemas/accounting_view_preferences/AccountingViewPreferencesResponse.yaml
    SupplierFieldPreference:
      $ref: ./schemas/accounting_view_preferences/SupplierFieldPreference.yaml
    SupplierField:
      $ref: ./schemas/accounting_view_preferences/SupplierField.yaml
    SupplierFieldSyncType:
      $ref: ./schemas/accounting_view_preferences/SupplierFieldSyncType.yaml
    ActionMeta:
      $ref: ./schemas/accounting_view_preferences/ActionMeta.yaml
    DisplayMeta:
      $ref: ./schemas/accounting_view_preferences/DisplayMeta.yaml
    CodeText:
      $ref: ./schemas/accounting_view_preferences/CodeText.yaml
    Expense:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the expense
          example: b8e7c123-4567-89ab-cdef-123456789012
        expenseSubType:
          anyOf:
            - $ref: '#/components/schemas/ExpenseSubtype'
            - type: 'null'
          description: Subtype of the expense
        bookingText:
          type:
            - string
            - 'null'
          description: Booking text associated with the expense
          example: Travel booking - Conference 2024
        description:
          type:
            - string
            - 'null'
          description: Description of the expense
          example: Office supplies
        createTime:
          type: string
          format: date-time
          description: Creation timestamp (ISO-8601)
          example: '2024-01-15T10:30:00Z'
        updateTime:
          type: string
          format: date-time
          description: Last update timestamp (ISO-8601)
          example: '2024-01-15T14:45:00Z'
        expenseMetadata:
          anyOf:
            - $ref: '#/components/schemas/ExpenseMetadata'
            - type: 'null'
          description: Type-specific metadata containing additional information for this expense
        organisationId:
          type: string
          format: uuid
          description: Unique identifier of the organisation the expense is attributed to
          example: a1b2c3d4-5678-9abc-def0-123456789012
        createdBy:
          type: string
          format: uuid
          description: ID of the user who created the expense
          example: e5f6a7b8-1234-5678-9abc-def012345678
        expenseType:
          $ref: '#/components/schemas/ExpenseType'
          description: Type of the expense
        status:
          anyOf:
            - $ref: '#/components/schemas/ExpenseStatus'
            - type: 'null'
          description: Current status of the expense
        supplierId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the supplier associated with the expense
          example: c9d0e1f2-3456-7890-abcd-ef0123456789
        homeAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Expense amount in the organisation's home currency
          example:
            amount: '119.25'
            currency: USD
        expenseTime:
          type: string
          format: date-time
          description: |
            - For **CARD_TRANSACTION**, this field is the receipt date if a receipt exists, otherwise it is the transaction date.
            - For **INVOICE**, this field is the invoice date: Date on the invoice.
            - For **REIMBURSEMENT**, this field is the submitted date: Date the reimbursement was submitted.
          example: '2024-01-15T09:00:00Z'
        servicePeriodFrom:
          type:
            - string
            - 'null'
          format: date
          description: Start date of the service period (YYYY-MM-DD)
          example: '2024-01-01'
        servicePeriodTo:
          type:
            - string
            - 'null'
          format: date
          description: End date of the service period (YYYY-MM-DD)
          example: '2024-01-31'
        exportMetadata:
          anyOf:
            - $ref: '#/components/schemas/ExportMetadata'
            - type: 'null'
          description: Metadata related to expense export to accounting systems
        lines:
          type: array
          items:
            $ref: '#/components/schemas/ExpenseLine'
          default: []
          description: Expense line items
      required:
        - id
        - expenseType
        - createTime
        - updateTime
        - organisationId
        - createdBy
        - expenseTime
      description: |
        Expense structure containing both parent-level information and common metadata.

        **Common fields** are shared across all expense types and include basic information
        like timestamps, descriptions, and expense metadata.

        **Parent fields** represent the main expense record information including organization
        details, approval status, supplier information, and export metadata.

        **Expense lines** contain line-item details including amounts, tax information,
        cost center assignments, and line-specific hospitality data.
    ExpenseLine:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the expense
          example: 123e4567-e89b-12d3-a456-426614174000
        expenseType:
          $ref: '#/components/schemas/ExpenseType'
          description: Type of the expense
        expenseSubType:
          $ref: '#/components/schemas/ExpenseSubtype'
        bookingText:
          type:
            - string
            - 'null'
          description: Booking text associated with the expense
          example: Office Supplies - Paper
        description:
          type:
            - string
            - 'null'
          description: Description of the expense
          example: Monthly office paper supply order
        createTime:
          type: string
          format: date-time
          description: Creation timestamp (ISO-8601)
          example: '2023-10-01T10:00:00Z'
        updateTime:
          type: string
          format: date-time
          description: Last update timestamp (ISO-8601)
          example: '2023-10-01T15:30:00Z'
        expenseAccountId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the expense account assigned to this expense
          example: 123e4567-e89b-12d3-a456-426614174001
        taxRateId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the tax rate applied to this expense line
          example: 123e4567-e89b-12d3-a456-426614174002
        netAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Net amount of the expense line with currency
          example:
            amount: '100.50'
            currency: EUR
        netAmountOverride:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Override value for the net amount with currency
          example:
            amount: '105.00'
            currency: EUR
        netHomeAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Net amount of the expense line in the home currency
          example:
            amount: '95.75'
            currency: USD
        netHomeAmountOverride:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Override value for the net amount in the home currency
          example:
            amount: '100.25'
            currency: USD
        amount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Total amount of the expense line with currency
          example:
            amount: '120.60'
            currency: EUR
        homeAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Expense amount in the organisation's home currency
          example:
            amount: '114.90'
            currency: USD
        conversionRate:
          type:
            - number
            - 'null'
          format: double
          description: Exchange rate used to convert the expense amount to the home currency
          example: 1.0523
        grossAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Gross amount of the expense line with currency
          example:
            amount: '143.52'
            currency: EUR
        vatAmount:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: VAT amount applied to the expense line with currency
          example:
            amount: '22.92'
            currency: EUR
        vatAmountOverride:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Override value for the VAT amount with currency
          example:
            amount: '25.00'
            currency: EUR
        quantity:
          type:
            - integer
            - 'null'
          description: Quantity of items in the expense line
          example: 5
        unitPrice:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Price per unit with currency
          example:
            amount: '24.12'
            currency: EUR
        unitPriceOverride:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Override value for the unit price with currency
          example:
            amount: '25.00'
            currency: EUR
        grossPercentage:
          type:
            - number
            - 'null'
          format: double
          description: Gross percentage applied to the expense line
          example: 19
        hospitalityExpense:
          type: boolean
          default: false
          description: Indicates whether this expense line is a hospitality expense
          example: false
        internalParticipants:
          type: array
          items:
            $ref: '#/components/schemas/HospitalityExpenseParticipant'
          default: []
          description: Internal participants associated with this hospitality expense
        externalParticipants:
          type: array
          items:
            $ref: '#/components/schemas/HospitalityExpenseParticipant'
          default: []
          description: External participants associated with this hospitality expense
        tip:
          anyOf:
            - $ref: '#/components/schemas/Money'
            - type: 'null'
          description: Tip amount associated with this hospitality expense with currency
          example:
            amount: '15.50'
            currency: EUR
        hospitalityPurpose:
          type:
            - string
            - 'null'
          description: Purpose of this hospitality expense
          example: Client meeting dinner
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/ExpenseDimension'
          default: []
          description: |
            Accounting dimensions assigned to this expense line.
            Cost center and cost carrier dimensions have fixed dimension ids, while other dimensions have non-fixed UUIDs.
            Cost center dimension has id 00000000-0000-0000-0000-000000000001.
            Cost carrier dimension has id 00000000-0000-0000-0000-000000000002.
        expenseMetadata:
          anyOf:
            - $ref: '#/components/schemas/ExpenseMetadata'
            - type: 'null'
          description: Type-specific metadata containing additional information for this expense line
      required:
        - id
        - expenseType
    ExpensesResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Expense'
              description: Array of expenses
    CreateSupplierRequest:
      $ref: ./schemas/CreateSupplierRequest.yaml
    UpdateSupplierRequest:
      $ref: ./schemas/UpdateSupplierRequest.yaml
    UpdateSupplierAddressRequest:
      $ref: ./schemas/UpdateSupplierAddressRequest.yaml
    SupplierStatus:
      $ref: ./schemas/SupplierStatus.yaml
    SupplierPaymentMethod:
      $ref: ./schemas/SupplierPaymentMethod.yaml
    SupplierAddressRequest:
      $ref: ./schemas/SupplierAddress.yaml
    Supplier:
      $ref: ./schemas/Supplier.yaml
    SupplierResponse:
      $ref: ./schemas/SupplierResponse.yaml
    SuppliersResponse:
      $ref: ./schemas/SuppliersResponse.yaml
    Money:
      $ref: ./schemas/Money.yaml
    PaymentTermStatus:
      $ref: ./schemas/PaymentTermStatus.yaml
    PaymentTermDueDateCalculationType:
      $ref: ./schemas/PaymentTermDueDateCalculationType.yaml
    PaymentTermLine:
      $ref: ./schemas/PaymentTermLine.yaml
    PaymentTerm:
      $ref: ./schemas/PaymentTerm.yaml
    PaymentTermResponse:
      $ref: ./schemas/PaymentTermResponse.yaml
    PaymentTermsResponse:
      $ref: ./schemas/PaymentTermsResponse.yaml
    ExpenseAccount:
      $ref: ./schemas/ExpenseAccount.yaml
    ExpenseAccountStatus:
      $ref: ./schemas/ExpenseAccountStatus.yaml
    ExpenseAccountResponse:
      $ref: ./schemas/ExpenseAccountResponse.yaml
    ExpenseAccountsResponse:
      $ref: ./schemas/ExpenseAccountsResponse.yaml
    Dimension:
      $ref: ./schemas/Dimension.yaml
    DimensionStatus:
      $ref: ./schemas/DimensionStatus.yaml
    CreateDimensionRequest:
      $ref: ./schemas/CreateDimensionRequest.yaml
    UpdateDimensionRequest:
      $ref: ./schemas/UpdateDimensionRequest.yaml
    DimensionResponse:
      $ref: ./schemas/DimensionResponse.yaml
    DimensionsResponse:
      $ref: ./schemas/DimensionsResponse.yaml
    DimensionItem:
      $ref: ./schemas/DimensionItem.yaml
    DimensionItemStatus:
      $ref: ./schemas/DimensionItemStatus.yaml
    DimensionItemResponse:
      $ref: ./schemas/DimensionItemResponse.yaml
    DimensionItemsResponse:
      $ref: ./schemas/DimensionItemsResponse.yaml
    CreateDimensionItemRequest:
      $ref: ./schemas/CreateDimensionItemRequest.yaml
    UpdateDimensionItemRequest:
      $ref: ./schemas/UpdateDimensionItemRequest.yaml
    TaxRate:
      $ref: ./schemas/TaxRate.yaml
    TaxRateType:
      $ref: ./schemas/TaxRateType.yaml
    TaxRateStatus:
      $ref: ./schemas/TaxRateStatus.yaml
    TaxRateResponse:
      $ref: ./schemas/TaxRateResponse.yaml
    TaxRatesResponse:
      $ref: ./schemas/TaxRatesResponse.yaml
    UserStatus:
      $ref: ./schemas/UserStatus.yaml
    UserRole:
      $ref: ./schemas/UserRole.yaml
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the user
          example: e635c214-0f45-422f-91fd-b2a5f8b5ed43
        organisationId:
          type: string
          format: uuid
          description: Unique identifier of the organisation the user belongs to
          example: 47aa12f6-acf9-455f-9f3b-400e5c7a4862
        teamId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the team the user is assigned to
          example: 4504a597-fc5e-4825-a66d-39014cb65e98
        email:
          type:
            - string
            - 'null'
          format: email
          description: User's email address
          example: john.doe@getmoss.com
        firstName:
          type: string
          description: User's given name
          example: John
        lastName:
          type: string
          description: User's last name
          example: Doe
        managerId:
          type:
            - string
            - 'null'
          format: uuid
          description: User ID of the user's manager
          example: 6de6ae54-2971-49cf-bb80-164f84fa23b4
        status:
          $ref: '#/components/schemas/UserStatus'
        roles:
          type: array
          items:
            $ref: '#/components/schemas/UserRole'
          description: Roles currently assigned to the user
          example:
            - USER
            - TEAMLEAD
        createTime:
          type: string
          format: date-time
          description: Creation timestamp (ISO-8601)
          example: '2025-08-25T09:57:03.183Z'
        updateTime:
          type: string
          format: date-time
          description: Last update timestamp (ISO-8601)
          example: '2025-08-25T09:57:29.754Z'
      required:
        - id
        - organisationId
        - firstName
        - lastName
        - status
        - roles
        - createTime
        - updateTime
    UserResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/User'
    UsersResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/User'
              description: Array of users
    TeamStatus:
      $ref: ./schemas/TeamStatus.yaml
    Team:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the team
          example: f2abd010-9dbb-4897-b740-ad70b125c784
        organisationId:
          type: string
          format: uuid
          description: Unique identifier of the organisation the team belongs to
          example: 47aa12f6-acf9-455f-9f3b-400e5c7a4862
        departmentId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the department this team is part of
          example: 5b2deb68-b3c8-470e-885d-132af66de5bb
        teamLeadId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the user that leads the team
          example: 0114eda3-cb62-410a-8cd8-c4b33b235169
        name:
          type: string
          description: Team name
          example: Engineering
        status:
          $ref: '#/components/schemas/TeamStatus'
      required:
        - id
        - organisationId
        - name
        - status
    TeamResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/Team'
    TeamsResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Team'
              description: Array of teams
    Department:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the department
          example: 48d60159-2554-414e-ae5e-3177d12f4e4f
        organisationId:
          type: string
          format: uuid
          description: Unique identifier of the organisation the department belongs to
          example: 47aa12f6-acf9-455f-9f3b-400e5c7a4862
        ownerId:
          type:
            - string
            - 'null'
          format: uuid
          description: Unique identifier of the user this department belongs to
          example: 09f66a1d-73a1-48d6-950f-6ea27a647324
        name:
          type: string
          description: Department name
          example: Engineering
      required:
        - id
        - organisationId
        - name
    DepartmentResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/Department'
    DepartmentsResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Department'
              description: Array of departments
    FundingType:
      $ref: ./schemas/FundingType.yaml
    BankAccountStatus:
      $ref: ./schemas/bank_account/BankAccountStatus.yaml
    BankAccount:
      $ref: ./schemas/bank_account/BankAccount.yaml
    BankAccountBalance:
      type: object
      properties:
        balance:
          $ref: '#/components/schemas/Money'
        availableBalance:
          $ref: '#/components/schemas/Money'
      required:
        - balance
        - availableBalance
    BankAccountsResponse:
      $ref: ./schemas/bank_account/BankAccountsResponse.yaml
    BankAccountBalanceResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/BankAccountBalance'
    BankTransactionFeeType:
      $ref: ./schemas/bank_transaction/BankTransactionFeeType.yaml
    BankTransactionFee:
      $ref: ./schemas/bank_transaction/BankTransactionFee.yaml
    BankTransactionType:
      $ref: ./schemas/bank_transaction/BankTransactionType.yaml
    BankTransaction:
      $ref: ./schemas/bank_transaction/BankTransaction.yaml
    BankTransactionsResponse:
      $ref: ./schemas/bank_transaction/BankTransactionsResponse.yaml
    BankTransactionsSearchRequest:
      $ref: ./schemas/bank_transaction/BankTransactionsSearchRequest.yaml
    ReconciliationBankTransaction:
      $ref: ./schemas/reconciliation_bank_transaction/ReconciliationBankTransaction.yaml
    ReconciliationBankTransactionsResponse:
      $ref: ./schemas/reconciliation_bank_transaction/ReconciliationBankTransactionsResponse.yaml
    ReconciliationBankTransactionResponse:
      $ref: ./schemas/reconciliation_bank_transaction/ReconciliationBankTransactionResponse.yaml
    ReconciliationBankTransactionsSearchRequest:
      $ref: ./schemas/reconciliation_bank_transaction/ReconciliationBankTransactionsSearchRequest.yaml
    ReconciliationGeneralLedgerEntry:
      $ref: ./schemas/reconciliation_general_ledger_entry/ReconciliationGeneralLedgerEntry.yaml
    ReconciliationGeneralLedgerEntriesResponse:
      $ref: ./schemas/reconciliation_general_ledger_entry/ReconciliationGeneralLedgerEntriesResponse.yaml
    ReconciliationGeneralLedgerEntryResponse:
      $ref: ./schemas/reconciliation_general_ledger_entry/ReconciliationGeneralLedgerEntryResponse.yaml
    ReconciliationGeneralLedgerEntriesSearchRequest:
      $ref: ./schemas/reconciliation_general_ledger_entry/ReconciliationGeneralLedgerEntriesSearchRequest.yaml
    ReconciliationMatchingGroup:
      $ref: ./schemas/reconciliation_matching_group/ReconciliationMatchingGroup.yaml
    ReconciliationMatchingGroupResponse:
      $ref: ./schemas/reconciliation_matching_group/ReconciliationMatchingGroupResponse.yaml
    ReconciliationCreateMatchingGroupRequest:
      $ref: ./schemas/reconciliation_matching_group/ReconciliationCreateMatchingGroupRequest.yaml
    ReconciliationBankLedgerMapping:
      $ref: ./schemas/reconciliation_bank_ledger_mapping/ReconciliationBankLedgerMapping.yaml
    ReconciliationBankLedgerMappingsResponse:
      $ref: ./schemas/reconciliation_bank_ledger_mapping/ReconciliationBankLedgerMappingsResponse.yaml
    ReconciliationBankLedgerMappingResponse:
      $ref: ./schemas/reconciliation_bank_ledger_mapping/ReconciliationBankLedgerMappingResponse.yaml
    ReconciliationCreateBankLedgerMappingRequest:
      $ref: ./schemas/reconciliation_bank_ledger_mapping/ReconciliationCreateBankLedgerMappingRequest.yaml
    GeneralLedgerAccount:
      $ref: ./schemas/general_ledger_account/GeneralLedgerAccount.yaml
    GeneralLedgerAccountsResponse:
      $ref: ./schemas/general_ledger_account/GeneralLedgerAccountsResponse.yaml
    GeneralLedgerAccountResponse:
      $ref: ./schemas/general_ledger_account/GeneralLedgerAccountResponse.yaml
    GeneralLedgerAccountsSearchRequest:
      $ref: ./schemas/general_ledger_account/GeneralLedgerAccountsSearchRequest.yaml
    File:
      $ref: ./schemas/file/File.yaml
    FileSearchRequest:
      $ref: ./schemas/file/FileSearchRequest.yaml
    FileSearchResponse:
      $ref: ./schemas/file/FileSearchResponse.yaml
    FileEmbedding:
      $ref: ./schemas/file/FileEmbedding.yaml
    FileEmbeddingResponse:
      $ref: ./schemas/file/FileEmbeddingResponse.yaml
    DocumentEmbeddingsResponse:
      $ref: ./schemas/document/DocumentEmbeddingsResponse.yaml
    BaseResponse:
      type: object
      properties:
        data:
          description: The response data (can be array or object)
        meta:
          $ref: '#/components/schemas/ApiMeta'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ApiError'
          description: Array of errors (only present in error responses)
      required:
        - data
        - meta
    ApiMeta:
      $ref: ./schemas/ApiMeta.yaml
    PaginationMeta:
      type: object
      discriminator:
        propertyName: type
        mapping:
          offset: '#/components/schemas/OffsetPaginationMeta'
      oneOf:
        - $ref: '#/components/schemas/OffsetPaginationMeta'
    OffsetPaginationMeta:
      $ref: ./schemas/OffsetPaginationMeta.yaml
    ApiError:
      $ref: ./schemas/ApiError.yaml
    ErrorResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              description: Always null for error responses
            errors:
              type: array
              items:
                $ref: '#/components/schemas/ApiError'
              minItems: 1
    DocumentType:
      type: string
      description: Type of the document
      enum:
        - INVOICE
        - RECEIPT
        - REIMBURSEMENT_BUSINESS_EXPENSE
        - PURCHASE
        - SUPPORTING
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: INVOICE
    DocumentEntityType:
      type: string
      description: Type of entity the document is linked to
      enum:
        - CARD_TRANSACTION
        - INVOICE
        - REIMBURSEMENT_BUSINESS_EXPENSE
        - SUPPLIER
        - PURCHASE
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: INVOICE
    DocumentLink:
      type: object
      description: Link between a document and an entity
      properties:
        entityId:
          type: string
          format: uuid
          description: ID of the linked entity
          example: d52a7115-452e-493b-9f44-744734622c73
        entityType:
          $ref: '#/components/schemas/DocumentEntityType'
      required:
        - entityId
        - entityType
    DocumentIngestRequest:
      type: object
      description: Request payload for ingesting a document
      properties:
        type:
          $ref: '#/components/schemas/DocumentType'
        links:
          type: array
          items:
            $ref: '#/components/schemas/DocumentLink'
          description: Entities this document should be linked to
    DocumentIngestResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                  description: Unique identifier of the document
                  example: d52a7115-452e-493b-9f44-744734622c73
                fileIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: IDs of the files associated with this document
    DocumentSearchRequest:
      type: object
      description: Request for searching documents
      required:
        - pagination
      properties:
        filters:
          type: object
          description: Optional filters to narrow the search results
          properties:
            types:
              type: array
              items:
                $ref: '#/components/schemas/DocumentType'
              description: Filter by document types
            statuses:
              type: array
              items:
                $ref: '#/components/schemas/DocumentStatus'
              description: Filter by document processing statuses
            counterpartyIds:
              type: array
              items:
                type: string
                format: uuid
              description: Filter by counterparty UUIDs
            channels:
              type: array
              items:
                $ref: '#/components/schemas/DocumentChannel'
              description: Filter by document ingestion channels
            createdBy:
              type: array
              items:
                type: string
                format: uuid
              description: Filter by user IDs who created the documents
            createTimeFrom:
              type: string
              format: date-time
              description: Filter documents created at or after this timestamp (inclusive)
              example: '2024-01-01T00:00:00Z'
            createTimeTo:
              type: string
              format: date-time
              description: Filter documents created at or before this timestamp (inclusive)
              example: '2024-12-31T23:59:59Z'
            extractedDocumentTimeFrom:
              type: string
              format: date-time
              description: Filter by extracted document date from (inclusive)
              example: '2024-01-01T00:00:00Z'
            extractedDocumentTimeTo:
              type: string
              format: date-time
              description: Filter by extracted document date to (inclusive)
              example: '2024-12-31T23:59:59Z'
        pagination:
          type: object
          description: Pagination parameters
          properties:
            page:
              type: integer
              minimum: 1
              default: 1
              description: Page number (1-based)
              example: 1
            pageSize:
              type: integer
              minimum: 1
              maximum: 100
              default: 20
              description: Number of items per page
              example: 20
    DocumentSearchResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Document'
              description: List of documents matching the search criteria
    DocumentResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/Document'
    Document:
      type: object
      description: A document record with its processing state and extracted data
      required:
        - id
        - status
        - files
        - createdBy
        - createTime
        - updateTime
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the document
          example: d52a7115-452e-493b-9f44-744734622c73
        status:
          $ref: '#/components/schemas/DocumentStatus'
        type:
          $ref: '#/components/schemas/DocumentType'
        channel:
          $ref: '#/components/schemas/DocumentChannel'
        extractedDocumentTime:
          type: string
          format: date-time
          description: Date and time extracted from the document content
          example: '2024-03-15T00:00:00Z'
        amount:
          type: number
          description: Monetary amount extracted from the document
          example: 1250
        counterpartyId:
          type: string
          format: uuid
          description: UUID of the associated counterparty (supplier/vendor)
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        confidence:
          $ref: '#/components/schemas/DocumentConfidenceLevel'
        files:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/DocumentFile'
          description: Files attached to this document
        duplicates:
          type: array
          items:
            type: string
            format: uuid
          description: IDs of documents detected as duplicates of this one
        extractedFields:
          type: array
          items:
            $ref: '#/components/schemas/DocumentExtractedField'
          description: Fields extracted from the document during processing
        complianceCheck:
          $ref: '#/components/schemas/DocumentComplianceCheckOverallResult'
        createdBy:
          $ref: '#/components/schemas/DocumentActor'
        createTime:
          type: string
          format: date-time
          description: Timestamp when the document was created
          example: '2024-03-15T10:30:00Z'
        updateTime:
          type: string
          format: date-time
          description: Timestamp when the document was last updated
          example: '2024-03-15T11:00:00Z'
    DocumentStatus:
      type: string
      description: Processing status of the document
      enum:
        - CREATED
        - CLASSIFIED
        - FIELDS_EXTRACTED
        - COMPLIANCE_CHECKED
        - ENTITY_LINKED
        - DUPLICATE_CHECKED
        - SIMILARITY_CHECKED
        - CONFIDENCE_SCORED
        - LINKED
        - FAILED
        - DELETED
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: LINKED
    DocumentChannel:
      type: string
      description: Channel through which the document was received
      enum:
        - INBOX
        - WEB_USER
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: INBOX
    DocumentFile:
      type: object
      description: A file attached to a document
      required:
        - id
        - name
        - originalName
        - sizeBytes
        - type
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the file
          example: f1e2d3c4-b5a6-7890-abcd-ef1234567890
        name:
          type: string
          description: Stored file name
          example: invoice_2024_03.pdf
        originalName:
          type: string
          description: Original file name as uploaded
          example: Invoice March 2024.pdf
        storageLink:
          type: string
          description: URL to access the file content
          example: https://storage.example.com/files/f1e2d3c4
        sizeBytes:
          type: integer
          format: int64
          description: File size in bytes
          example: 204800
        type:
          type: string
          description: MIME type of the file
          example: application/pdf
    DocumentExtractedField:
      type: object
      description: A field extracted from the document during processing
      required:
        - id
        - fieldType
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the extracted field
          example: b2c3d4e5-f6a7-8901-bcde-f12345678901
        fieldType:
          $ref: '#/components/schemas/DocumentFieldType'
        fieldId:
          type: string
          format: uuid
          description: UUID reference to the linked dimension/entity
          example: c3d4e5f6-a7b8-9012-cdef-123456789012
        extractedLineId:
          type: string
          format: uuid
          description: UUID of the extracted invoice line this field belongs to
          example: d4e5f6a7-b8c9-0123-defa-234567890123
        fileId:
          type: string
          format: uuid
          description: UUID of the file this field was extracted from
          example: e5f6a7b8-c9d0-1234-efab-345678901234
        boundingBox:
          type: object
          description: Location of the field within the document page
          properties:
            top:
              type: number
              format: double
              description: Top position as a fraction of page height
            left:
              type: number
              format: double
              description: Left position as a fraction of page width
            page:
              type: integer
              description: Page number (1-based) where the field was found
            width:
              type: number
              format: double
              description: Width as a fraction of page width
            height:
              type: number
              format: double
              description: Height as a fraction of page height
    DocumentFieldType:
      type: string
      description: Type of field extracted from the document
      enum:
        - SUPPLIER_ACCOUNT
        - EXPENSE_ACCOUNT
        - CATEGORY
        - VAT
        - VAT_AMOUNT_OVERRIDE
        - BOOKING_TEXT
        - DESCRIPTION
        - INVOICE_NUMBER
        - COST_CENTER
        - COST_CARRIER
        - DIMENSION
        - STATUS
        - EXPENSE_DATE
        - GROSS_AMOUNT
        - CURRENCY
        - TEAM
        - PAYMENT_TERM
        - PAYMENT_REFERENCE
        - PAYMENT_STATUS
        - SPLIT
        - SUB_INVOICES
        - DUE_DATE
        - DELIVERY_DATE
        - QUANTITY
        - HOSPITALITY_ENABLED
        - INTERNAL_PARTICIPANTS
        - EXTERNAL_PARTICIPANTS
        - TIP
        - HOSPITALITY_PURPOSE
        - HOSPITALITY_RESTAURANT_NAME
        - HOSPITALITY_ADDRESS_TEXT
        - DELIVERY_DATE_OR_SERVICE_PERIOD
        - RECEIPT_REQUIREMENT
        - NET_AMOUNT
        - VAT_AMOUNT
        - VERIFIER
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: GROSS_AMOUNT
    DocumentConfidenceLevel:
      type: object
      description: Confidence score for an extraction result
      required:
        - score
      properties:
        score:
          type: number
          format: double
          minimum: 0
          maximum: 1
          description: Confidence score between 0.0 (no confidence) and 1.0 (full confidence)
          example: 0.95
        comment:
          type: string
          description: Optional explanation of the confidence score
          example: High confidence based on exact text match
    DocumentActor:
      type: object
      description: The actor who performed an action on the document
      required:
        - id
        - type
      properties:
        id:
          type: string
          format: uuid
          description: UUID of the actor
          example: afafb141-9033-49bd-ad2a-c425e6329173
        type:
          $ref: '#/components/schemas/DocumentActorType'
    DocumentActorType:
      type: string
      description: Type of actor that created or modified the document
      enum:
        - USER
        - SYSTEM
        - AGENT
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: USER
    DocumentComplianceCheckOverallResult:
      type: object
      description: Aggregate compliance check result for a document.
      required:
        - entityCountry
        - validationType
        - overallStatus
        - individualResults
        - createdBy
      properties:
        entityCountry:
          type: string
          description: ISO 3166-1 alpha-2 country code of the entity the check was run against
          example: DE
        validationType:
          $ref: '#/components/schemas/DocumentComplianceCheckValidationType'
        overallStatus:
          $ref: '#/components/schemas/DocumentComplianceCheckOverallStatus'
        individualResults:
          type: array
          items:
            $ref: '#/components/schemas/DocumentComplianceCheckIndividualResult'
          description: Results of each individual compliance check that was run
        narrative:
          $ref: '#/components/schemas/DocumentComplianceCheckNarrative'
        createdBy:
          $ref: '#/components/schemas/DocumentActor'
    DocumentComplianceCheckValidationType:
      type: string
      description: Depth of compliance validation performed
      enum:
        - FULL
        - SIMPLIFIED
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: FULL
    DocumentComplianceCheckOverallStatus:
      type: string
      description: |
        Aggregate compliance outcome for the whole document, derived from its checks.
        - COMPLIANT: All checks are COMPLIANT or NOT_APPLICABLE.
        - NOT_COMPLIANT: One or more checks are NOT_COMPLIANT.
        - CHECK_FAILED: No checks are NOT_COMPLIANT, but one or more are CHECK_FAILED.
      enum:
        - COMPLIANT
        - NOT_COMPLIANT
        - CHECK_FAILED
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: COMPLIANT
    DocumentComplianceCheckIndividualResult:
      type: object
      description: Result of a single compliance check.
      required:
        - checkId
        - status
      properties:
        checkId:
          type: string
          description: Identifier of the compliance rule that was evaluated
          example: vat_rate_valid
        status:
          $ref: '#/components/schemas/DocumentComplianceCheckIndividualStatus'
        confidence:
          type: number
          format: double
          description: Confidence score for this check's result
          example: 0.9
        failMessage:
          type:
            - string
            - 'null'
          description: Explanation of the failure, present when status is NOT_COMPLIANT
          example: VAT rate 7% does not match the expected 19% for this supply type.
        evidence:
          $ref: '#/components/schemas/DocumentComplianceCheckEvidence'
    DocumentComplianceCheckIndividualStatus:
      type: string
      description: |
        Outcome of a single compliance check.
        - COMPLIANT: Check ran and the document satisfies the rule.
        - NOT_COMPLIANT: Check ran and found a violation.
        - NOT_APPLICABLE: Rule doesn't apply to this document (e.g. non-EU supplier, simplified validation).
        - CHECK_FAILED: Check could not reach a verdict — missing prerequisite or unavailable service.
      enum:
        - COMPLIANT
        - NOT_COMPLIANT
        - NOT_APPLICABLE
        - CHECK_FAILED
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: COMPLIANT
    DocumentComplianceCheckEvidence:
      type: object
      description: Supporting data for a compliance check result.
      properties:
        fieldId:
          type: string
          format: uuid
          description: Reference to the extracted field that triggered this check
          example: c3d4e5f6-a7b8-9012-cdef-123456789012
        extractedValue:
          type:
            - string
            - 'null'
          description: Value extracted from the document (serialized as string)
          example: '7'
        expectedValue:
          type:
            - string
            - 'null'
          description: Value the check expected (serialized as string)
          example: '19'
        valueType:
          $ref: '#/components/schemas/DocumentComplianceCheckEvidenceValueType'
        source:
          $ref: '#/components/schemas/DocumentComplianceCheckEvidenceSource'
    DocumentComplianceCheckEvidenceValueType:
      type: string
      description: Type of the extracted/expected values in the evidence
      enum:
        - AMOUNT
        - DATE
        - NUMBER
        - PERCENTAGE
        - TEXT
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: PERCENTAGE
    DocumentComplianceCheckEvidenceSource:
      type: string
      description: Where the evidence for a compliance check came from
      enum:
        - DOCUMENT
        - UNKNOWN_DEFAULT_OPEN_API
      default: UNKNOWN_DEFAULT_OPEN_API
      example: DOCUMENT
    DocumentComplianceCheckNarrative:
      type: object
      description: |
        Human-readable explanation of a non-compliant or check-failed document. Present only when overallStatus is NOT_COMPLIANT or CHECK_FAILED. Each message array is expected to contain one entry per supported language.
      required:
        - accountantMessage
      properties:
        accountantMessage:
          type: array
          description: Explanation shown to the accountant
          items:
            $ref: '#/components/schemas/DocumentComplianceCheckLocalizedText'
        employeeMessage:
          type: array
          description: Explanation shown to the employee who submitted the document
          items:
            $ref: '#/components/schemas/DocumentComplianceCheckLocalizedText'
        supplierMessage:
          type: array
          description: Draft email body requesting a corrected document from the supplier
          items:
            $ref: '#/components/schemas/DocumentComplianceCheckLocalizedText'
    DocumentComplianceCheckLocalizedText:
      type: object
      required:
        - locale
        - text
      properties:
        locale:
          type: string
          description: IETF BCP 47 locale code
          example: en-GB
        text:
          type: string
  headers:
    X-RateLimit-Limit:
      description: Maximum number of requests allowed in the current rate limit window for the used scope.
      schema:
        type: integer
        example: 30
    X-RateLimit-Remaining:
      description: Number of requests remaining in the current rate limit window.
      schema:
        type: integer
        example: 25
    X-RateLimit-Reset:
      description: Unix timestamp (seconds since epoch, UTC) when the rate limit window resets.
      schema:
        type: integer
        format: int64
        example: 1704067200
    X-RateLimit-Scope:
      description: 'The OAuth scope bucket to which this rate limit applies: `read` or `write`.'
      schema:
        type: string
        example: read
    Retry-After:
      description: Number of seconds to wait before retrying. Only present on 429 Too Many Requests responses.
      schema:
        type: integer
        example: 15
  responses:
    BadGateway:
      description: Bad gateway. An upstream service could not be reached.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            data: null
            meta:
              apiVersion: 1.6.0
              tracingId: 026cb8891f2f1bc257f6876ce4878a3f
            errors:
              - type: ERR_BAD_GATEWAY
                title: Bad gateway
                detail: An upstream service could not be reached. Please try again later.
                status: 502
                instance: /v1/teams
    GatewayTimeout:
      description: Gateway timeout. An upstream service did not respond in time.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            data: null
            meta:
              apiVersion: 1.6.0
              tracingId: 026cb8891f2f1bc257f6876ce4878a3f
            errors:
              - type: ERR_GATEWAY_TIMEOUT
                title: Upstream service timed out
                detail: An upstream service did not respond in time. Please try again.
                status: 504
                instance: /v1/teams
    ServiceUnavailable:
      description: Service temporarily unavailable. An upstream service returned a 503 error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            data: null
            meta:
              apiVersion: 1.6.0
              tracingId: 026cb8891f2f1bc257f6876ce4878a3f
            errors:
              - type: ERR_SERVICE_UNAVAILABLE
                title: Service unavailable
                detail: An upstream service is temporarily unavailable. Please try again later.
                status: 503
                instance: /v1/expenses
    TooManyRequests:
      description: Rate limit exceeded. Reduce request frequency and retry after the indicated number of seconds.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Scope:
          $ref: '#/components/headers/X-RateLimit-Scope'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            data: null
            meta:
              apiVersion: 1.6.0
              tracingId: 026cb8891f2f1bc257f6876ce4878a3f
            errors:
              - type: ERR_RATE_LIMIT_EXCEEDED
                title: Rate limit exceeded
                detail: API rate limit exceeded. Please reduce request frequency or contact support.
                status: 429
                instance: /v1/expenses
security:
  - BearerAuth: []
paths:
  /v1/expenses:
    get:
      tags:
        - Expenses
      operationId: getExpenses
      summary: Get all expenses
      description: Returns a paginated list of expenses with optional type filtering and entity ID filtering
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: type
          in: query
          description: Filter by expense types (can specify multiple)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/HeaderExpenseType'
            uniqueItems: true
            maxItems: 3
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: status
          in: query
          description: Filter by expense status (can specify multiple)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/ExpenseStatus'
            uniqueItems: true
            maxItems: 13
        - name: export_status
          in: query
          description: Filter by export status (can specify multiple)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/ExportStatus'
            uniqueItems: true
            maxItems: 5
        - name: id
          in: query
          description: Filter by specific expense entity IDs (can specify multiple, max 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            uniqueItems: true
            maxItems: 100
        - name: create_date__gte
          in: query
          description: Filter expenses created on or after this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2024-01-15'
        - name: create_date__lte
          in: query
          description: Filter expenses created on or before this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2024-12-31'
        - name: expense_date__gte
          in: query
          description: Filter expenses with expense date on or after this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2024-01-15'
        - name: expense_date__lte
          in: query
          description: Filter expenses with expense date on or before this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2024-12-31'
        - name: update_time__gte
          in: query
          description: Filter expenses last updated on or after this timestamp (ISO-8601)
          required: false
          schema:
            type: string
            format: date-time
            example: '2023-10-01T15:30:00Z'
        - name: update_time__lte
          in: query
          description: Filter expenses last updated before this timestamp (ISO-8601)
          required: false
          schema:
            type: string
            format: date-time
            example: '2023-10-01T15:30:00Z'
        - name: sort
          in: query
          description: |
            Sort expenses by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - status: Sort by expense status
            - create_time: Sort by creation time
            - home_amount: Sort by expense amount
            - expense_time: Sort by expense date/time
          required: false
          schema:
            type: string
            pattern: ^[+-]?(status|create_time|home_amount|expense_time)$
            example: '-home_amount'
      responses:
        '200':
          description: Expenses data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExpensesResponse'
        '400':
          description: Bad request (e.g., invalid type parameter)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/expense-accounts/{expenseAccountId}:
    get:
      tags:
        - Expense Accounts
      operationId: getExpenseAccountById
      summary: Get expense account by ID
      description: Returns expense account information for a specific expense account ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: expenseAccountId
          in: path
          description: UUID of the expense account to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: 837574c8-e813-4bb3-b31e-c7358758c29c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Expense account information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExpenseAccountResponse'
        '400':
          description: Bad request (e.g., invalid expense account ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Expense account not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/expense-accounts:
    get:
      tags:
        - Expense Accounts
      operationId: getAllExpenseAccounts
      summary: Get all expense accounts
      description: Returns a paginated list of expense accounts with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific expense account IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - 837574c8-e813-4bb3-b31e-c7358758c29c
              - c3f67167-4927-4c6d-ae90-d4b55b211786
        - name: status
          in: query
          description: Filter by expense account status
          required: false
          schema:
            $ref: '#/components/schemas/ExpenseAccountStatus'
        - name: account_number__gte
          in: query
          description: Filter by minimum account number (greater than or equal to)
          required: false
          schema:
            type: string
            example: '400000'
        - name: account_number__lte
          in: query
          description: Filter by maximum account number (less than or equal to)
          required: false
          schema:
            type: string
            example: '500000'
        - name: sort
          in: query
          description: |
            Sort expense accounts by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - name: Sort by expense account name (ascending only)
            - account_number: Sort by account number (ascending or descending)
            - create_time: Sort by creation time (descending only, use "-create_time")
          required: false
          schema:
            type: string
            pattern: ^([+]?name|[+-]?account_number|-create_time)$
            example: name
      responses:
        '200':
          description: Expense accounts retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExpenseAccountsResponse'
        '400':
          description: Bad request (e.g., invalid query parameters, user has multiple organizations)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/dimensions/{dimensionId}:
    get:
      tags:
        - Dimensions
      operationId: getDimensionById
      summary: Get dimension by ID
      description: Returns dimension information for a specific dimension ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Dimension data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DimensionResponse'
        '400':
          description: Bad request (e.g., invalid dimension ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Dimension not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    patch:
      tags:
        - Dimensions
      operationId: updateDimension
      summary: Update an existing dimension
      description: |
        Updates an existing dimension in the accounting system for the authenticated user's organization.
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension to update
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateDimensionRequest'
      responses:
        '200':
          description: Dimension updated successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., missing required fields, invalid data format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: |
            Payment required - Multiple Dimensions billing module is not activated for this organization (`ERR_MODULE_NOT_ACTIVATED`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Dimension not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: |
            Conflict - Cannot update dimension:
            * Dimension with the same name already exists (`ERR_DIMENSION_NAME_ALREADY_EXISTS`)
            * Dimension with the same ERP ID already exists (`ERR_DIMENSION_ERP_ID_ALREADY_EXISTS`)
            * Dimension is inactive/deleted (`ERR_DIMENSION_INACTIVE`)
            * Cost centers and cost carriers cannot be modified (`ERR_COST_CENTER_IMMUTABLE`, `ERR_COST_CARRIER_IMMUTABLE`)
            * Resource is managed by an active accounting integration (`ERR_MANAGED_RESOURCE_IMMUTABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/dimensions:
    get:
      tags:
        - Dimensions
      operationId: getAllDimensions
      summary: Get all dimensions
      description: Returns a list of dimensions within the authenticated user's organization. No pagination is supported as the volume is expected to be small (max 50 entries).
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Dimensions data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DimensionsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    post:
      tags:
        - Dimensions
      operationId: createDimension
      summary: Create a new dimension
      description: Creates a new dimension in the accounting system for the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDimensionRequest'
      responses:
        '201':
          description: Dimension created successfully
          headers:
            Location:
              description: URI of the created dimension resource
              schema:
                type: string
                example: /v1/dimensions/af5f2270-9a4d-467f-9ca7-69562369979c
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., missing required fields, invalid data format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: |
            Payment required - Multiple Dimensions billing module is not activated for this organization (`ERR_MODULE_NOT_ACTIVATED`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: |
            Conflict - Resource already exists or managed:
            * Dimension with the same name already exists (`ERR_DIMENSION_NAME_ALREADY_EXISTS`)
            * Dimension with the same ERP ID already exists (`ERR_DIMENSION_ERP_ID_ALREADY_EXISTS`)
            * Resource is managed by an active accounting integration (`ERR_MANAGED_RESOURCE_IMMUTABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/dimensions/{dimensionId}/items/{dimensionItemId}:
    get:
      tags:
        - Dimension Items
      operationId: getDimensionItemById
      summary: Get dimension item by ID
      description: Returns dimension item information for a specific dimension item ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: dimensionItemId
          in: path
          description: UUID of the dimension item to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: 8a684e99-d19b-4f83-8239-7ac89aa1109c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Dimension item information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DimensionItemResponse'
        '400':
          description: Bad request (e.g., invalid dimension item ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Dimension item not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    patch:
      tags:
        - Dimension Items
      operationId: updateDimensionItem
      summary: Update dimension item
      description: |
        Updates an existing dimension item within the authenticated user's organization.
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: dimensionItemId
          in: path
          description: UUID of the dimension item to update
          required: true
          schema:
            type: string
            format: uuid
            example: 8a684e99-d19b-4f83-8239-7ac89aa1109c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateDimensionItemRequest'
      responses:
        '200':
          description: Dimension item updated successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., invalid data format, validation errors, dimension item not found)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: |
            Not found:
            * Dimension not found
            * Dimension item not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: |
            Conflict - Update failed:
            * Dimension item with the same value already exists (`ERR_DIMENSION_ITEM_VALUE_ALREADY_EXISTS`)
            * Dimension is inactive (`ERR_DIMENSION_INACTIVE`)
            * Dimension item is inactive (`ERR_DIMENSION_ITEM_INACTIVE`)
            * Resource is managed by an active accounting integration (`ERR_MANAGED_RESOURCE_IMMUTABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/dimensions/{dimensionId}/items:
    get:
      tags:
        - Dimension Items
      operationId: getAllDimensionItems
      summary: Get all dimension items
      description: Returns a paginated list of dimension items with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
            example: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            example: 20
        - name: status
          in: query
          description: Filter by dimension item status
          required: false
          schema:
            $ref: '#/components/schemas/DimensionItemStatus'
        - name: id
          in: query
          description: Filter by dimension item IDs (max 100, must be unique)
          required: false
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - 8a684e99-d19b-4f83-8239-7ac89aa1109c
              - 659d57b2-5b7d-4200-8c70-19d094f469d8
        - name: create_date__gte
          in: query
          description: Filter by minimum creation date (inclusive)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-01'
        - name: create_date__lte
          in: query
          description: Filter by maximum creation date (inclusive)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-31'
        - name: update_date__gte
          in: query
          description: Filter by minimum update date (inclusive)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-01'
        - name: update_date__lte
          in: query
          description: Filter by maximum update date (inclusive)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-31'
        - name: sort
          in: query
          description: |
            Sort dimension items by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - name: Sort by dimension item name (ascending only)
            - update_time: Sort by last update time (descending only, use "-update_time")
          required: false
          schema:
            type: string
            pattern: ^([+]?name|-update_time)$
            example: name
      responses:
        '200':
          description: Dimension items data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DimensionItemsResponse'
        '400':
          description: Bad request (e.g., invalid pagination parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    post:
      tags:
        - Dimension Items
      operationId: createDimensionItem
      summary: Create a new dimension item
      description: Creates a new dimension item for the specified dimension within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: dimensionId
          in: path
          description: UUID of the dimension
          required: true
          schema:
            type: string
            format: uuid
            example: af5f2270-9a4d-467f-9ca7-69562369979c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDimensionItemRequest'
      responses:
        '201':
          description: Dimension item created successfully
          headers:
            Location:
              schema:
                type: string
              description: URI of the created dimension item
              example: /v1/dimensions/af5f2270-9a4d-467f-9ca7-69562369979c/items/8a684e99-d19b-4f83-8239-7ac89aa1109c
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., invalid data format, validation errors)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: |
            Payment required - Multiple Dimensions billing module is not activated for this organization (`ERR_MODULE_NOT_ACTIVATED`).
            Only applies when creating items for custom dimensions (not cost centers or cost carriers).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Dimension not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: |
            Conflict - Resource conflict:
            * Dimension item with the same value already exists (`ERR_DIMENSION_ITEM_VALUE_ALREADY_EXISTS`)
            * Dimension is inactive (`ERR_DIMENSION_INACTIVE`)
            * Resource is managed by an active accounting integration (`ERR_MANAGED_RESOURCE_IMMUTABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/suppliers/{supplierId}:
    get:
      tags:
        - Suppliers
      operationId: getSupplierById
      summary: Get supplier by ID
      description: Returns supplier information for a specific supplier ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: supplierId
          in: path
          description: UUID of the supplier to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: b4b13057-eb46-412e-a70c-2e2eaf5b8f69
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Supplier information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupplierResponse'
        '400':
          description: Bad request (e.g., invalid supplier ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Supplier not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    patch:
      tags:
        - Suppliers
      operationId: updateSupplier
      summary: Update supplier (partial update)
      description: |
        Partially updates a supplier in the authenticated user's organization. 
        All fields are optional. Fields can be updated, cleared (set to null), or left unchanged (not provided).

        **Update behavior:**
        - Field not provided = no change to existing value
        - Field set to null = clear the field value
        - Field set to value = update to new value
      security:
        - BearerAuth: []
      parameters:
        - name: supplierId
          in: path
          description: UUID of the supplier to update
          required: true
          schema:
            type: string
            format: uuid
            example: b4b13057-eb46-412e-a70c-2e2eaf5b8f69
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSupplierRequest'
      responses:
        '200':
          description: Supplier updated successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., invalid data format, empty update request, missing required fields based on accounting integration)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Supplier not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Conflict - update would create duplicate supplier number or violates accounting integration immutability rules
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Unprocessable entity - a referenced entity (expense account, cost carrier, payment term, VAT rate, or team) does not exist or is not active
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/suppliers:
    get:
      tags:
        - Suppliers
      operationId: getAllSuppliers
      summary: Get all suppliers
      description: Returns a paginated list of suppliers with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific supplier IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - b4b13057-eb46-412e-a70c-2e2eaf5b8f69
              - 2494898f-c5cb-4290-b745-713857e44d31
        - name: status
          in: query
          description: Filter by supplier status
          required: false
          schema:
            $ref: '#/components/schemas/SupplierStatus'
        - name: create_date__gte
          in: query
          description: Filter suppliers created on or after this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-01'
        - name: create_date__lte
          in: query
          description: Filter suppliers created on or before this date (ISO 8601 date format)
          required: false
          schema:
            type: string
            format: date
            example: '2026-01-31'
        - name: update_time__gte
          in: query
          description: Filter suppliers last updated on or after this timestamp (ISO-8601)
          required: false
          schema:
            type: string
            format: date-time
            example: '2026-01-10T10:00:00Z'
        - name: update_time__lte
          in: query
          description: Filter suppliers last updated before this timestamp (ISO-8601)
          required: false
          schema:
            type: string
            format: date-time
            example: '2026-01-10T11:00:00Z'
        - name: sort
          in: query
          description: |
            Sort suppliers by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - name: Sort by supplier name
            - supplier_number: Sort by supplier number
          required: false
          schema:
            type: string
            pattern: ^[+-]?(name|supplier_number)$
            example: name
      responses:
        '200':
          description: Suppliers data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuppliersResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    post:
      tags:
        - Suppliers
      operationId: createSupplier
      summary: Create a new supplier
      description: Creates a new supplier in the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSupplierRequest'
      responses:
        '201':
          description: Supplier created successfully
          headers:
            Location:
              description: URI of the created supplier resource
              schema:
                type: string
                example: /v1/suppliers/b4b13057-eb46-412e-a70c-2e2eaf5b8f69
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseResponse'
        '400':
          description: Bad request (e.g., missing required fields, invalid data format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Conflict - a supplier with the same number already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Unprocessable entity - a referenced entity (expense account, cost carrier, payment term, VAT rate, or team) does not exist or is not active
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/payment-terms/{paymentTermId}:
    get:
      tags:
        - Payment Terms
      operationId: getPaymentTermById
      summary: Get payment term by ID
      description: Returns payment term information for a specific payment term ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: paymentTermId
          in: path
          description: UUID of the payment term to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: a9aa1059-30d7-4df9-a335-c7339c682d74
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Payment term information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentTermResponse'
        '400':
          description: Bad request (e.g., invalid payment term ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Payment term not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/payment-terms:
    get:
      tags:
        - Payment Terms
      operationId: getAllPaymentTerms
      summary: Get all payment terms
      description: Returns a paginated list of payment terms with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific payment term IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - a9aa1059-30d7-4df9-a335-c7339c682d74
        - name: status
          in: query
          description: Filter by payment term status (can specify multiple)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/PaymentTermStatus'
            maxItems: 3
            uniqueItems: true
        - name: sort
          in: query
          description: |
            Sort payment terms by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - number: Sort by reference number
            - description: Sort by description
            - create_time: Sort by creation timestamp
          required: false
          schema:
            type: string
            pattern: ^[+-]?(number|description|create_time)$
            example: number
      responses:
        '200':
          description: Payment terms data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentTermsResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/tax-rates/{taxRateId}:
    get:
      tags:
        - Tax Rates
      operationId: getTaxRateById
      summary: Get tax rate by ID
      description: Returns tax rate information for a specific tax rate ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: taxRateId
          in: path
          description: UUID of the tax rate to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: e852fc73-1f4b-4ce7-937f-ac5ee2231ddc
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Tax rate information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaxRateResponse'
        '400':
          description: Bad request (e.g., invalid tax rate ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Tax rate not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/tax-rates:
    get:
      tags:
        - Tax Rates
      operationId: getAllTaxRates
      summary: Get all tax rates
      description: Returns a paginated list of tax rates with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific tax rate IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - e852fc73-1f4b-4ce7-937f-ac5ee2231ddc
              - edf85ea7-654e-4ada-839e-4b9149adb720
        - name: status
          in: query
          description: Filter by tax rate status
          required: false
          schema:
            $ref: '#/components/schemas/TaxRateStatus'
        - name: type
          in: query
          description: Filter by tax rate type (can specify multiple)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/TaxRateType'
            uniqueItems: true
            maxItems: 1
        - name: sort
          in: query
          description: |
            Sort tax rates by field with direction. Format: [+|-]field_name
            Use + for ascending (default) or - for descending order.
            Only one sort field allowed at a time.

            Available fields:
            - name: Sort by tax rate name
            - rate: Sort by tax rate value
            - code: Sort by tax rate code
            - update_time: Sort by last update time (descending only, use "-update_time")
          required: false
          schema:
            type: string
            pattern: ^[+-]?(name|rate|code)|-update_time$
            example: name
      responses:
        '200':
          description: Tax rates data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaxRatesResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/users/{userId}:
    get:
      tags:
        - Users
      operationId: getUserById
      summary: Get user by ID
      description: Returns user information for a specific user ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: userId
          in: path
          description: UUID of the user to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: e635c214-0f45-422f-91fd-b2a5f8b5ed43
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: User information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '400':
          description: Bad request (e.g., invalid user ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: User not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/users:
    get:
      tags:
        - Users
      operationId: getAllUsers
      summary: Get all users
      description: Returns a paginated list of users with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific user IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - e635c214-0f45-422f-91fd-b2a5f8b5ed43
              - c1a77dd8-1e68-48b3-b733-89e3ace3c546
        - name: status
          in: query
          description: Filter by user status (can specify multiple, up to 5)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/UserStatus'
            maxItems: 5
            uniqueItems: true
        - name: role
          in: query
          description: Filter by user role (can specify multiple, up to 8)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              $ref: '#/components/schemas/UserRole'
            maxItems: 8
            uniqueItems: true
        - name: sort
          in: query
          description: |
            Sort users by name with direction. Format: [+|-]name
            Use + for ascending (default) or - for descending order.

            Available fields:
            - name: Sort by full name (first name + last name)
          required: false
          schema:
            type: string
            pattern: ^[+-]?name$
            example: name
      responses:
        '200':
          description: Users data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UsersResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/teams/{teamId}:
    get:
      tags:
        - Teams
      operationId: getTeamById
      summary: Get team by ID
      description: Returns team information for a specific team ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: teamId
          in: path
          description: UUID of the team to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: f2abd010-9dbb-4897-b740-ad70b125c784
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Team data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Team not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/teams:
    get:
      tags:
        - Teams
      operationId: getAllTeams
      summary: Get all teams
      description: Returns a paginated list of teams with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific team IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - f2abd010-9dbb-4897-b740-ad70b125c784
              - 6e08b45b-aebd-4374-b9e4-7c07a2c7a75f
        - name: department_id
          in: query
          description: Filter by department IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - 5b2deb68-b3c8-470e-885d-132af66de5bb
              - 48d60159-2554-414e-ae5e-3177d12f4e4f
        - name: status
          in: query
          description: Filter by team status
          required: false
          schema:
            $ref: '#/components/schemas/TeamStatus'
        - name: sort
          in: query
          description: |
            Sort teams by name with direction. Format: [+|-]name
            Use + for ascending (default) or - for descending order.

            Available fields:
            - name: Sort by team name
          required: false
          schema:
            type: string
            pattern: ^[+-]?name$
            example: name
      responses:
        '200':
          description: Teams data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamsResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/departments/{departmentId}:
    get:
      tags:
        - Departments
      operationId: getDepartmentById
      summary: Get department by ID
      description: Returns department information for a specific department ID within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: departmentId
          in: path
          description: UUID of the department to retrieve
          required: true
          schema:
            type: string
            format: uuid
            example: 48d60159-2554-414e-ae5e-3177d12f4e4f
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Department data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Department not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/departments:
    get:
      tags:
        - Departments
      operationId: getAllDepartments
      summary: Get all departments
      description: Returns a paginated list of departments with optional filtering and sorting within the authenticated user's organization
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
        - name: page
          in: query
          description: Page number for pagination (1-based)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: Number of items per page
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: id
          in: query
          description: Filter by specific department IDs (can specify multiple, up to 100)
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              format: uuid
            maxItems: 100
            uniqueItems: true
            example:
              - 48d60159-2554-414e-ae5e-3177d12f4e4f
              - 5b2deb68-b3c8-470e-885d-132af66de5bb
        - name: sort
          in: query
          description: |
            Sort departments by name with direction. Format: [+|-]name
            Use + for ascending (default) or - for descending order.

            Available fields:
            - name: Sort by department name
          required: false
          schema:
            type: string
            pattern: ^[+-]?name$
            example: name
      responses:
        '200':
          description: Departments data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentsResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/bank-accounts:
    get:
      tags:
        - Bank Accounts
      operationId: getAllBankAccounts
      summary: Get all bank accounts
      description: |
        Returns all Moss bank accounts (wallets) for the authenticated user's organisation.

        Each bank account has a funding type (`CREDIT` for credit-funded accounts, `DEBIT` for debit-funded accounts), a currency, and a status (`ACTIVE` or `CLOSED`). Use the returned `id` to retrieve the account balance or to filter bank transactions.

        No pagination is supported as the number of bank accounts per organisation is small.
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Bank accounts data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BankAccountsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/bank-accounts/{bankAccountId}/balance:
    get:
      tags:
        - Bank Accounts
      operationId: getBankAccountBalance
      summary: Get bank account balance
      description: |
        Returns the current balance for a specific bank account within the authenticated user's organisation.

        The response includes two balance fields:
        - `balance`: The current ledger balance of the account.
        - `availableBalance`: The balance available for spending, which may be lower than `balance` due to pending or reserved transactions.

        Both values are returned as Money objects with `amount` and `currency` fields.
      security:
        - BearerAuth: []
      parameters:
        - name: bankAccountId
          in: path
          description: UUID of the bank account to retrieve balance information for
          required: true
          schema:
            type: string
            format: uuid
            example: 837574c8-e813-4bb3-b31e-c7358758c29c
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: Bank account balance information retrieved successfully
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BankAccountBalanceResponse'
        '400':
          description: Bad request (e.g., invalid bank account ID format)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Bank account not found in organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/bank-transactions/search-query:
    post:
      tags:
        - Bank Transactions
      operationId: searchBankTransactions
      summary: Search bank transactions
      description: |
        Returns a paginated list of bank transactions for a specific bank account within a date range.

        Bank transactions represent money movements in Moss wallets, including card purchases, payouts to external bank accounts, top-ups, ATM withdrawals, and repayments. Each transaction includes the total amount (inclusive of any fees), booking and value dates, and an array of associated fees broken down by type (e.g., FX fee, payment fee).

        The request body requires three filters: `bankAccountId`, `bookingDateFrom`, and `bookingDateTo`. Pagination and sorting are optional; results are sorted by `bookingDate` descending by default.
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BankTransactionsSearchRequest'
      responses:
        '200':
          description: Bank transactions data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BankTransactionsResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/files/search-query:
    post:
      tags:
        - Files
      operationId: searchFiles
      summary: Search files
      description: |
        Returns a paginated list of files for the authenticated user's organization based on the provided search criteria.

        _Note_: If you specify expense IDs, only files directly attached to those expenses will be returned. If you wish to find
        files attached the line objects you must request those separately.
      security:
        - BearerAuth: []
      parameters:
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FileSearchRequest'
      responses:
        '200':
          description: Files data
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileSearchResponse'
        '400':
          description: Bad request (e.g., invalid filter parameters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (e.g., user has no organizations, insufficient scope privileges)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /v1/files/{fileId}/content:
    get:
      tags:
        - Files
      operationId: downloadFile
      summary: Download a file's content
      description: Downloads file contents by its ID
      security:
        - BearerAuth: []
      parameters:
        - name: fileId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: moss-trace-id
          in: header
          description: Request tracing identifier
          required: false
          schema:
            type: string
            example: 026cb8891f2f1bc257f6876ce4878a3f
      responses:
        '200':
          description: File content
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="document.pdf"
            moss-trace-id:
              description: Request tracing identifier echoed from the request, or a generated one if not provided
              schema:
                type: string
                example: 026cb8891f2f1bc257f6876ce4878a3f
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Scope:
              $ref: '#/components/headers/X-RateLimit-Scope'
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
