openapi: 3.0.3
info:
  title: 'Tidybill API Documentation'
  description: 'REST API for managing invoices, clients, projects, time tracking, and more.'
  version: 1.0.0
servers:
  -
    url: 'https://tidybill.app'
tags:
  -
    name: Authentication
    description: ''
  -
    name: Companies
    description: ''
  -
    name: Clients
    description: ''
  -
    name: Invoices
    description: ''
  -
    name: Quotes
    description: ''
  -
    name: Projects
    description: ''
  -
    name: 'Time Tracking'
    description: "\nManage time entries for tracking billable and non-billable work. Time entries store a `date` and `duration`\n(in seconds). The `started_at`, `ended_at`, and `is_running` fields in the response are read-only and only\npopulated when using the Timer endpoints (start/stop/current/discard). To create a manual time entry,\nprovide `date` and `duration` only. The `hourly_rate` is auto-resolved from project, service, or company\ndefaults if not provided. All money values (`hourly_rate`, `calculated_amount`) are integers in cents."
  -
    name: Services
    description: ''
  -
    name: Expenses
    description: ''
  -
    name: Credits
    description: ''
  -
    name: 'Recurring Invoices'
    description: ''
  -
    name: Billing
    description: ''
  -
    name: Settings
    description: ''
  -
    name: 'Bank Accounts'
    description: ''
  -
    name: Imports
    description: ''
  -
    name: 'Stripe Connect'
    description: ''
  -
    name: 'API Tokens'
    description: ''
  -
    name: Invitations
    description: ''
  -
    name: 'Client Portal'
    description: ''
  -
    name: Dashboard
    description: ''
  -
    name: Reports
    description: ''
  -
    name: 'Activity Log'
    description: ''
components:
  securitySchemes:
    default:
      type: http
      scheme: bearer
      description: 'Create a personal access token from **Settings > API** in your Tidybill dashboard. Requires a Pro plan.'
security:
  -
    default: []
paths:
  /api/auth/register:
    post:
      summary: Register
      operationId: register
      description: ''
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1
                    name: John
                    email: john@example.com
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1
                      name:
                        type: string
                        example: John
                      email:
                        type: string
                        example: john@example.com
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: zbailey@example.net
                password:
                  type: string
                  description: 'Must be at least 8 characters.'
                  example: '-0pBNvYgxw'
              required:
                - name
                - email
                - password
      security: []
  /api/auth/login:
    post:
      summary: Login
      operationId: login
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1
                    name: John
                    email: john@example.com
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1
                      name:
                        type: string
                        example: John
                      email:
                        type: string
                        example: john@example.com
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Invalid credentials.'
                properties:
                  message:
                    type: string
                    example: 'Invalid credentials.'
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: 'Must be a valid email address.'
                  example: gbailey@example.net
                password:
                  type: string
                  description: ''
                  example: '|]|{+-'
              required:
                - email
                - password
      security: []
  /api/auth/forgot-password:
    post:
      summary: 'Send password reset link'
      operationId: sendPasswordResetLink
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'If an account exists, a reset link has been sent.'
                properties:
                  message:
                    type: string
                    example: 'If an account exists, a reset link has been sent.'
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: 'Must be a valid email address.'
                  example: gbailey@example.net
              required:
                - email
      security: []
  /api/auth/reset-password:
    post:
      summary: 'Reset password'
      operationId: resetPassword
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Password has been reset.'
                properties:
                  message:
                    type: string
                    example: 'Password has been reset.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This password reset token is invalid.'
                properties:
                  message:
                    type: string
                    example: 'This password reset token is invalid.'
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
                  description: ''
                  example: architecto
                email:
                  type: string
                  description: 'Must be a valid email address.'
                  example: zbailey@example.net
                password:
                  type: string
                  description: 'Must be at least 8 characters.'
                  example: '-0pBNvYgxw'
              required:
                - token
                - email
                - password
      security: []
  /api/auth/google:
    get:
      summary: 'Redirect to Google OAuth'
      operationId: redirectToGoogleOAuth
      description: ''
      parameters: []
      responses:
        302:
          description: ''
          content:
            text/plain:
              schema:
                oneOf:
                  -
                    description: 'Redirect to Google'
                    type: string
                    example: ''
                  -
                    description: ''
                    type: string
                    example: "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta http-equiv=\"refresh\" content=\"0;url='https://accounts.google.com/o/oauth2/auth?client_id=122074070973-q2t44i2big2vg257o5bkbn5kjhuu1d34.apps.googleusercontent.com&amp;redirect_uri=https%3A%2F%2Ftidybill.app%2Fapi%2Fauth%2Fgoogle%2Fcallback&amp;scope=openid+profile+email&amp;response_type=code'\" />\n\n        <title>Redirecting to https://accounts.google.com/o/oauth2/auth?client_id=122074070973-q2t44i2big2vg257o5bkbn5kjhuu1d34.apps.googleusercontent.com&amp;redirect_uri=https%3A%2F%2Ftidybill.app%2Fapi%2Fauth%2Fgoogle%2Fcallback&amp;scope=openid+profile+email&amp;response_type=code</title>\n    </head>\n    <body>\n        Redirecting to <a href=\"https://accounts.google.com/o/oauth2/auth?client_id=122074070973-q2t44i2big2vg257o5bkbn5kjhuu1d34.apps.googleusercontent.com&amp;redirect_uri=https%3A%2F%2Ftidybill.app%2Fapi%2Fauth%2Fgoogle%2Fcallback&amp;scope=openid+profile+email&amp;response_type=code\">https://accounts.google.com/o/oauth2/auth?client_id=122074070973-q2t44i2big2vg257o5bkbn5kjhuu1d34.apps.googleusercontent.com&amp;redirect_uri=https%3A%2F%2Ftidybill.app%2Fapi%2Fauth%2Fgoogle%2Fcallback&amp;scope=openid+profile+email&amp;response_type=code</a>.\n    </body>\n</html>"
      tags:
        - Authentication
      security: []
  /api/auth/google/callback:
    get:
      summary: 'Google OAuth callback'
      operationId: googleOAuthCallback
      description: ''
      parameters: []
      responses:
        302:
          description: ''
          content:
            text/plain:
              schema:
                oneOf:
                  -
                    description: 'Redirect to frontend after authentication'
                    type: string
                    example: ''
                  -
                    description: ''
                    type: string
                    example: "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta http-equiv=\"refresh\" content=\"0;url='https://tidybill.app/login?error=google_auth_failed'\" />\n\n        <title>Redirecting to https://tidybill.app/login?error=google_auth_failed</title>\n    </head>\n    <body>\n        Redirecting to <a href=\"https://tidybill.app/login?error=google_auth_failed\">https://tidybill.app/login?error=google_auth_failed</a>.\n    </body>\n</html>"
      tags:
        - Authentication
      security: []
  /api/auth/logout:
    post:
      summary: Logout
      operationId: logout
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Logged out.'
                properties:
                  message:
                    type: string
                    example: 'Logged out.'
      tags:
        - Authentication
  /api/auth/user:
    get:
      summary: 'Get authenticated user'
      operationId: getAuthenticatedUser
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 8
                    name: 'Morgan Hirthe'
                    email: dare.emelie@example.com
                    avatar_url: null
                    current_company_id: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 8
                      name:
                        type: string
                        example: 'Morgan Hirthe'
                      email:
                        type: string
                        example: dare.emelie@example.com
                      avatar_url:
                        type: string
                        example: null
                        nullable: true
                      current_company_id:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Authentication
    put:
      summary: 'Update authenticated user'
      operationId: updateAuthenticatedUser
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9
                    name: 'Ms. Elisabeth Okuneva'
                    email: gulgowski.asia@example.com
                    avatar_url: null
                    current_company_id: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 9
                      name:
                        type: string
                        example: 'Ms. Elisabeth Okuneva'
                      email:
                        type: string
                        example: gulgowski.asia@example.com
                      avatar_url:
                        type: string
                        example: null
                        nullable: true
                      current_company_id:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Authentication
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: ''
                  example: null
  /api/companies:
    get:
      summary: 'List companies'
      operationId: listCompanies
      description: 'Returns all companies the authenticated user is a member of, regardless of role.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 15
                      uuid: 0db07a5e-1aa6-4165-ba1e-f4c0990f7705
                      name: 'Price Ltd'
                      legal_name: null
                      email: dare.emelie@baumbach.org
                      phone: null
                      address_line_1: null
                      address_line_2: null
                      city: null
                      state: null
                      postal_code: null
                      country: null
                      currency: USD
                      tax_number: null
                      logo_path: null
                      invoice_prefix: INV-
                      quote_prefix: QUO-
                      invoice_layout: classic
                      default_payment_terms: 30
                      default_hourly_rate: null
                      default_tax_name_1: null
                      default_tax_rate_1: null
                      default_tax_name_2: null
                      default_tax_rate_2: null
                      late_fee_type: null
                      late_fee_value: null
                      late_fee_days: null
                      created_at: '2026-04-05T19:38:14.000000Z'
                      updated_at: '2026-04-05T19:38:14.000000Z'
                    -
                      id: 16
                      uuid: 81e00a44-fe6f-47fe-9604-3dc4ac4cae5a
                      name: 'Leuschke, Bauch and Fritsch'
                      legal_name: null
                      email: isidro.mclaughlin@smitham.com
                      phone: null
                      address_line_1: null
                      address_line_2: null
                      city: null
                      state: null
                      postal_code: null
                      country: null
                      currency: USD
                      tax_number: null
                      logo_path: null
                      invoice_prefix: INV-
                      quote_prefix: QUO-
                      invoice_layout: classic
                      default_payment_terms: 30
                      default_hourly_rate: null
                      default_tax_name_1: null
                      default_tax_rate_1: null
                      default_tax_name_2: null
                      default_tax_rate_2: null
                      late_fee_type: null
                      late_fee_value: null
                      late_fee_days: null
                      created_at: '2026-04-05T19:38:14.000000Z'
                      updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 15
                        uuid: 0db07a5e-1aa6-4165-ba1e-f4c0990f7705
                        name: 'Price Ltd'
                        legal_name: null
                        email: dare.emelie@baumbach.org
                        phone: null
                        address_line_1: null
                        address_line_2: null
                        city: null
                        state: null
                        postal_code: null
                        country: null
                        currency: USD
                        tax_number: null
                        logo_path: null
                        invoice_prefix: INV-
                        quote_prefix: QUO-
                        invoice_layout: classic
                        default_payment_terms: 30
                        default_hourly_rate: null
                        default_tax_name_1: null
                        default_tax_rate_1: null
                        default_tax_name_2: null
                        default_tax_rate_2: null
                        late_fee_type: null
                        late_fee_value: null
                        late_fee_days: null
                        created_at: '2026-04-05T19:38:14.000000Z'
                        updated_at: '2026-04-05T19:38:14.000000Z'
                      -
                        id: 16
                        uuid: 81e00a44-fe6f-47fe-9604-3dc4ac4cae5a
                        name: 'Leuschke, Bauch and Fritsch'
                        legal_name: null
                        email: isidro.mclaughlin@smitham.com
                        phone: null
                        address_line_1: null
                        address_line_2: null
                        city: null
                        state: null
                        postal_code: null
                        country: null
                        currency: USD
                        tax_number: null
                        logo_path: null
                        invoice_prefix: INV-
                        quote_prefix: QUO-
                        invoice_layout: classic
                        default_payment_terms: 30
                        default_hourly_rate: null
                        default_tax_name_1: null
                        default_tax_rate_1: null
                        default_tax_name_2: null
                        default_tax_rate_2: null
                        late_fee_type: null
                        late_fee_value: null
                        late_fee_days: null
                        created_at: '2026-04-05T19:38:14.000000Z'
                        updated_at: '2026-04-05T19:38:14.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 15
                        uuid:
                          type: string
                          example: 0db07a5e-1aa6-4165-ba1e-f4c0990f7705
                        name:
                          type: string
                          example: 'Price Ltd'
                        legal_name:
                          type: string
                          example: null
                          nullable: true
                        email:
                          type: string
                          example: dare.emelie@baumbach.org
                        phone:
                          type: string
                          example: null
                          nullable: true
                        address_line_1:
                          type: string
                          example: null
                          nullable: true
                        address_line_2:
                          type: string
                          example: null
                          nullable: true
                        city:
                          type: string
                          example: null
                          nullable: true
                        state:
                          type: string
                          example: null
                          nullable: true
                        postal_code:
                          type: string
                          example: null
                          nullable: true
                        country:
                          type: string
                          example: null
                          nullable: true
                        currency:
                          type: string
                          example: USD
                        tax_number:
                          type: string
                          example: null
                          nullable: true
                        logo_path:
                          type: string
                          example: null
                          nullable: true
                        invoice_prefix:
                          type: string
                          example: INV-
                        quote_prefix:
                          type: string
                          example: QUO-
                        invoice_layout:
                          type: string
                          example: classic
                        default_payment_terms:
                          type: integer
                          example: 30
                        default_hourly_rate:
                          type: string
                          example: null
                          nullable: true
                        default_tax_name_1:
                          type: string
                          example: null
                          nullable: true
                        default_tax_rate_1:
                          type: string
                          example: null
                          nullable: true
                        default_tax_name_2:
                          type: string
                          example: null
                          nullable: true
                        default_tax_rate_2:
                          type: string
                          example: null
                          nullable: true
                        late_fee_type:
                          type: string
                          example: null
                          nullable: true
                        late_fee_value:
                          type: string
                          example: null
                          nullable: true
                        late_fee_days:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:14.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Companies
    post:
      summary: 'Create a company'
      operationId: createACompany
      description: "Creates a company, attaches the authenticated user as owner, and creates a default invoice template. Returns 403 if the user's plan company limit is reached."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 17
                    uuid: 3e26903d-5044-4d8b-ab0e-e1e541451f00
                    name: 'Considine LLC'
                    legal_name: null
                    email: ernie.nitzsche@ankunding.biz
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 17
                      uuid:
                        type: string
                        example: 3e26903d-5044-4d8b-ab0e-e1e541451f00
                      name:
                        type: string
                        example: 'Considine LLC'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: ernie.nitzsche@ankunding.biz
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: "You've reached your free plan limit of 1 companies. Please upgrade."
                  upgrade_required: true
                properties:
                  message:
                    type: string
                    example: "You've reached your free plan limit of 1 companies. Please upgrade."
                  upgrade_required:
                    type: boolean
                    example: true
      tags:
        - Companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                legal_name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: ashly64@example.com
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: v
                  nullable: true
                address_line_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: d
                  nullable: true
                address_line_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: l
                  nullable: true
                city:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                state:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                postal_code:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: ikhwaykcmyuwpwlv
                  nullable: true
                country:
                  type: string
                  description: 'Must be 2 characters.'
                  example: qw
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: rsi
                  nullable: true
                tax_number:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: t
                  nullable: true
                invoice_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: cpscql
                  nullable: true
                quote_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: dzsnrw
                  nullable: true
                default_payment_terms:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 365.'
                  example: 19
                  nullable: true
                default_hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 33
                  nullable: true
                default_tax_name_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                default_tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 17
                  nullable: true
                default_tax_name_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: v
                  nullable: true
                default_tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 24
                  nullable: true
              required:
                - name
  '/api/companies/{company_id}':
    get:
      summary: 'Get a company'
      operationId: getACompany
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 18
                    uuid: 1f26aac2-cf55-4962-b801-73a762a46bee
                    name: 'Price Ltd'
                    legal_name: null
                    email: dare.emelie@baumbach.org
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 18
                      uuid:
                        type: string
                        example: 1f26aac2-cf55-4962-b801-73a762a46bee
                      name:
                        type: string
                        example: 'Price Ltd'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: dare.emelie@baumbach.org
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Companies
    put:
      summary: 'Update a company'
      operationId: updateACompany
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 19
                    uuid: 426db81d-0fdf-43ee-9022-d67d5e37bcd8
                    name: 'Considine LLC'
                    legal_name: null
                    email: ernie.nitzsche@ankunding.biz
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 19
                      uuid:
                        type: string
                        example: 426db81d-0fdf-43ee-9022-d67d5e37bcd8
                      name:
                        type: string
                        example: 'Considine LLC'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: ernie.nitzsche@ankunding.biz
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                legal_name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: ashly64@example.com
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: v
                  nullable: true
                address_line_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: d
                  nullable: true
                address_line_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: l
                  nullable: true
                city:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                state:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                postal_code:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: ikhwaykcmyuwpwlv
                  nullable: true
                country:
                  type: string
                  description: 'Must be 2 characters.'
                  example: qw
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: rsi
                  nullable: true
                tax_number:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: t
                  nullable: true
                invoice_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: cpscql
                  nullable: true
                quote_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: dzsnrw
                  nullable: true
                default_payment_terms:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 365.'
                  example: 19
                  nullable: true
                default_hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 33
                  nullable: true
                default_tax_name_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                default_tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 17
                  nullable: true
                default_tax_name_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: v
                  nullable: true
                default_tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 24
                  nullable: true
              required:
                - name
    delete:
      summary: 'Delete a company'
      operationId: deleteACompany
      description: 'Only the company owner can delete a company. Returns 403 for any other role.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Only the owner can delete a company.'
                properties:
                  message:
                    type: string
                    example: 'Only the owner can delete a company.'
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/switch':
    post:
      summary: 'Switch active company'
      operationId: switchActiveCompany
      description: "Updates the user's `current_company_id` so subsequent requests default to this company."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 20
                    uuid: f7fb15be-3a49-4a8b-bca9-17805160b129
                    name: 'Price Ltd'
                    legal_name: null
                    email: dare.emelie@baumbach.org
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 20
                      uuid:
                        type: string
                        example: f7fb15be-3a49-4a8b-bca9-17805160b129
                      name:
                        type: string
                        example: 'Price Ltd'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: dare.emelie@baumbach.org
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members':
    get:
      summary: 'List company members'
      operationId: listCompanyMembers
      description: 'Returns all users belonging to the company with their assigned role from the pivot table.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      name: John
                      email: john@example.com
                      role: owner
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        name: John
                        email: john@example.com
                        role: owner
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: John
                        email:
                          type: string
                          example: john@example.com
                        role:
                          type: string
                          example: owner
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members/invite':
    post:
      summary: 'Invite a member'
      operationId: inviteAMember
      description: 'Creates an invitation record with a 7-day expiry and emails the invite link. Returns 422 if the user is already a member or a pending invitation exists.'
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Invitation sent.'
                  data:
                    id: 1
                    email: jane@example.com
                    role: member
                    expires_at: '2026-04-12T00:00:00.000000Z'
                properties:
                  message:
                    type: string
                    example: 'Invitation sent.'
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1
                      email:
                        type: string
                        example: jane@example.com
                      role:
                        type: string
                        example: member
                      expires_at:
                        type: string
                        example: '2026-04-12T00:00:00.000000Z'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'User is already a member.'
                properties:
                  message:
                    type: string
                    example: 'User is already a member.'
      tags:
        - Companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: 'Must be a valid email address.'
                  example: gbailey@example.net
                role:
                  type: string
                  description: ''
                  example: architecto
              required:
                - email
                - role
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members/invitations':
    get:
      summary: 'List pending invitations'
      operationId: listPendingInvitations
      description: 'Returns all non-expired, non-accepted invitations for the company, ordered by most recent.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      email: jane@example.com
                      role: member
                      invited_by: John
                      expires_at: '2026-04-12T00:00:00.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        email: jane@example.com
                        role: member
                        invited_by: John
                        expires_at: '2026-04-12T00:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        email:
                          type: string
                          example: jane@example.com
                        role:
                          type: string
                          example: member
                        invited_by:
                          type: string
                          example: John
                        expires_at:
                          type: string
                          example: '2026-04-12T00:00:00.000000Z'
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members/invitations/{invitation_id}':
    delete:
      summary: 'Cancel an invitation'
      operationId: cancelAnInvitation
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
      -
        in: path
        name: invitation_id
        description: 'The ID of the invitation.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members/invitations/{invitation_id}/resend':
    post:
      summary: 'Resend an invitation'
      operationId: resendAnInvitation
      description: 'Regenerates the invitation token, extends the expiry by 7 days, and re-sends the email. Returns 422 if the invitation has already been accepted.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Invitation resent.'
                properties:
                  message:
                    type: string
                    example: 'Invitation resent.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Invitation already accepted.'
                properties:
                  message:
                    type: string
                    example: 'Invitation already accepted.'
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
      -
        in: path
        name: invitation_id
        description: 'The ID of the invitation.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/companies/{company_id}/members/{user_id}':
    put:
      summary: "Update a member's role"
      operationId: updateAMembersRole
      description: 'Changes the role on the company-user pivot. The owner role cannot be changed; returns 403 if attempted.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Member updated.'
                properties:
                  message:
                    type: string
                    example: 'Member updated.'
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Cannot change the owner role.'
                properties:
                  message:
                    type: string
                    example: 'Cannot change the owner role.'
      tags:
        - Companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                role:
                  type: string
                  description: ''
                  example: architecto
              required:
                - role
    delete:
      summary: 'Remove a member'
      operationId: removeAMember
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Cannot remove the company owner.'
                properties:
                  message:
                    type: string
                    example: 'Cannot remove the company owner.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'You cannot remove yourself.'
                properties:
                  message:
                    type: string
                    example: 'You cannot remove yourself.'
      tags:
        - Companies
    parameters:
      -
        in: path
        name: company_id
        description: 'The ID of the company.'
        example: 2
        required: true
        schema:
          type: integer
      -
        in: path
        name: user_id
        description: 'The ID of the user.'
        example: 2
        required: true
        schema:
          type: integer
  /api/clients/bulk-action:
    post:
      summary: 'Bulk action on clients'
      operationId: bulkActionOnClients
      description: 'Supported actions: `archive`, `unarchive`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: archive
                  enum:
                    - archive
                    - unarchive
                    - delete
              required:
                - action
  /api/clients:
    get:
      summary: 'List clients'
      operationId: listClients
      description: 'Supports name/email search and archived state filtering. Results are paginated and include active/archived counts in the meta.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 128
                      uuid: d7179e59-a6fc-4543-ad1f-1a32b4d1bde9
                      name: 'Price Ltd'
                      email: dare.emelie@example.com
                      phone: '+14324666067'
                      address_line_1: '26432 Leuschke Throughway Apt. 227'
                      address_line_2: null
                      city: 'Lake Audreyborough'
                      state: Montana
                      postal_code: 36080-0782
                      country: VG
                      currency: USD
                      payment_terms: 30
                      notes: null
                      is_archived: false
                      created_at: '2026-04-05T19:38:14.000000Z'
                      updated_at: '2026-04-05T19:38:14.000000Z'
                    -
                      id: 129
                      uuid: 5631d5c1-7b94-445f-b78a-96df0d7280b0
                      name: 'Fahey, Cartwright and Balistreri'
                      email: florence.wolff@example.net
                      phone: 1-346-252-9368
                      address_line_1: '20568 Murl Villages'
                      address_line_2: null
                      city: 'New Modesta'
                      state: Iowa
                      postal_code: 57582-4237
                      country: TM
                      currency: USD
                      payment_terms: 30
                      notes: null
                      is_archived: false
                      created_at: '2026-04-05T19:38:14.000000Z'
                      updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 128
                        uuid: d7179e59-a6fc-4543-ad1f-1a32b4d1bde9
                        name: 'Price Ltd'
                        email: dare.emelie@example.com
                        phone: '+14324666067'
                        address_line_1: '26432 Leuschke Throughway Apt. 227'
                        address_line_2: null
                        city: 'Lake Audreyborough'
                        state: Montana
                        postal_code: 36080-0782
                        country: VG
                        currency: USD
                        payment_terms: 30
                        notes: null
                        is_archived: false
                        created_at: '2026-04-05T19:38:14.000000Z'
                        updated_at: '2026-04-05T19:38:14.000000Z'
                      -
                        id: 129
                        uuid: 5631d5c1-7b94-445f-b78a-96df0d7280b0
                        name: 'Fahey, Cartwright and Balistreri'
                        email: florence.wolff@example.net
                        phone: 1-346-252-9368
                        address_line_1: '20568 Murl Villages'
                        address_line_2: null
                        city: 'New Modesta'
                        state: Iowa
                        postal_code: 57582-4237
                        country: TM
                        currency: USD
                        payment_terms: 30
                        notes: null
                        is_archived: false
                        created_at: '2026-04-05T19:38:14.000000Z'
                        updated_at: '2026-04-05T19:38:14.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 128
                        uuid:
                          type: string
                          example: d7179e59-a6fc-4543-ad1f-1a32b4d1bde9
                        name:
                          type: string
                          example: 'Price Ltd'
                        email:
                          type: string
                          example: dare.emelie@example.com
                        phone:
                          type: string
                          example: '+14324666067'
                        address_line_1:
                          type: string
                          example: '26432 Leuschke Throughway Apt. 227'
                        address_line_2:
                          type: string
                          example: null
                          nullable: true
                        city:
                          type: string
                          example: 'Lake Audreyborough'
                        state:
                          type: string
                          example: Montana
                        postal_code:
                          type: string
                          example: 36080-0782
                        country:
                          type: string
                          example: VG
                        currency:
                          type: string
                          example: USD
                        payment_terms:
                          type: integer
                          example: 30
                        notes:
                          type: string
                          example: null
                          nullable: true
                        is_archived:
                          type: boolean
                          example: false
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:14.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Clients
    post:
      summary: 'Create a client'
      operationId: createAClient
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 130
                    uuid: d0ae1404-48ba-4c80-81e2-18f7d3562e16
                    name: "Fritsch-O'Keefe"
                    email: carey67@example.com
                    phone: 283.476.7809
                    address_line_1: '67339 Gaylord Meadow Suite 788'
                    address_line_2: null
                    city: Verliebury
                    state: Colorado
                    postal_code: 61747-3805
                    country: KP
                    currency: USD
                    payment_terms: 30
                    notes: null
                    is_archived: false
                    created_at: '2026-04-05T19:38:14.000000Z'
                    updated_at: '2026-04-05T19:38:14.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 130
                      uuid:
                        type: string
                        example: d0ae1404-48ba-4c80-81e2-18f7d3562e16
                      name:
                        type: string
                        example: "Fritsch-O'Keefe"
                      email:
                        type: string
                        example: carey67@example.com
                      phone:
                        type: string
                        example: 283.476.7809
                      address_line_1:
                        type: string
                        example: '67339 Gaylord Meadow Suite 788'
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: Verliebury
                      state:
                        type: string
                        example: Colorado
                      postal_code:
                        type: string
                        example: 61747-3805
                      country:
                        type: string
                        example: KP
                      currency:
                        type: string
                        example: USD
                      payment_terms:
                        type: integer
                        example: 30
                      notes:
                        type: string
                        example: null
                        nullable: true
                      is_archived:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:14.000000Z'
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: zbailey@example.net
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: i
                  nullable: true
                address_line_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'y'
                  nullable: true
                address_line_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: v
                  nullable: true
                city:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: d
                  nullable: true
                state:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: l
                  nullable: true
                postal_code:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: jnikhwaykcmyuwpw
                  nullable: true
                country:
                  type: string
                  description: 'Must be 2 characters.'
                  example: lv
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: qwr
                  nullable: true
                payment_terms:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 365.'
                  example: 10
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 5000 characters.'
                  example: i
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
              required:
                - name
  '/api/clients/{id}':
    get:
      summary: 'Get a client'
      operationId: getAClient
      description: "Includes the client's contacts and associated projects."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 131
                    uuid: fe59f5ac-a325-4d12-9ea3-af4385b8a9b1
                    name: 'Price Ltd'
                    email: dare.emelie@example.com
                    phone: '+14324666067'
                    address_line_1: '26432 Leuschke Throughway Apt. 227'
                    address_line_2: null
                    city: 'Lake Audreyborough'
                    state: Montana
                    postal_code: 36080-0782
                    country: VG
                    currency: USD
                    payment_terms: 30
                    notes: null
                    is_archived: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 131
                      uuid:
                        type: string
                        example: fe59f5ac-a325-4d12-9ea3-af4385b8a9b1
                      name:
                        type: string
                        example: 'Price Ltd'
                      email:
                        type: string
                        example: dare.emelie@example.com
                      phone:
                        type: string
                        example: '+14324666067'
                      address_line_1:
                        type: string
                        example: '26432 Leuschke Throughway Apt. 227'
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: 'Lake Audreyborough'
                      state:
                        type: string
                        example: Montana
                      postal_code:
                        type: string
                        example: 36080-0782
                      country:
                        type: string
                        example: VG
                      currency:
                        type: string
                        example: USD
                      payment_terms:
                        type: integer
                        example: 30
                      notes:
                        type: string
                        example: null
                        nullable: true
                      is_archived:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
    put:
      summary: 'Update a client'
      operationId: updateAClient
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 132
                    uuid: b185a943-0f68-43f2-93a2-d720c608be3a
                    name: "Fritsch-O'Keefe"
                    email: carey67@example.com
                    phone: 283.476.7809
                    address_line_1: '67339 Gaylord Meadow Suite 788'
                    address_line_2: null
                    city: Verliebury
                    state: Colorado
                    postal_code: 61747-3805
                    country: KP
                    currency: USD
                    payment_terms: 30
                    notes: null
                    is_archived: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 132
                      uuid:
                        type: string
                        example: b185a943-0f68-43f2-93a2-d720c608be3a
                      name:
                        type: string
                        example: "Fritsch-O'Keefe"
                      email:
                        type: string
                        example: carey67@example.com
                      phone:
                        type: string
                        example: 283.476.7809
                      address_line_1:
                        type: string
                        example: '67339 Gaylord Meadow Suite 788'
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: Verliebury
                      state:
                        type: string
                        example: Colorado
                      postal_code:
                        type: string
                        example: 61747-3805
                      country:
                        type: string
                        example: KP
                      currency:
                        type: string
                        example: USD
                      payment_terms:
                        type: integer
                        example: 30
                      notes:
                        type: string
                        example: null
                        nullable: true
                      is_archived:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: zbailey@example.net
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: i
                  nullable: true
                address_line_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'y'
                  nullable: true
                address_line_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: v
                  nullable: true
                city:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: d
                  nullable: true
                state:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: l
                  nullable: true
                postal_code:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: jnikhwaykcmyuwpw
                  nullable: true
                country:
                  type: string
                  description: 'Must be 2 characters.'
                  example: lv
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: qwr
                  nullable: true
                payment_terms:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 365.'
                  example: 10
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 5000 characters.'
                  example: i
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
    delete:
      summary: 'Delete a client'
      operationId: deleteAClient
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Clients
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/move':
    post:
      summary: 'Move client to another company'
      operationId: moveClientToAnotherCompany
      description: 'Moves the client and all their associated invoices, quotes, recurring invoices, projects, time entries, and expenses to the target company in a single transaction.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 133
                    uuid: 345c2f0a-3b35-4f33-a9d5-80a146687983
                    name: 'Bailey Ltd'
                    email: rempel.chadrick@example.org
                    phone: 1-973-868-2042
                    address_line_1: '77432 Amber Crossing'
                    address_line_2: null
                    city: Leuschkeland
                    state: Kentucky
                    postal_code: '25744'
                    country: MD
                    currency: USD
                    payment_terms: 30
                    notes: null
                    is_archived: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 133
                      uuid:
                        type: string
                        example: 345c2f0a-3b35-4f33-a9d5-80a146687983
                      name:
                        type: string
                        example: 'Bailey Ltd'
                      email:
                        type: string
                        example: rempel.chadrick@example.org
                      phone:
                        type: string
                        example: 1-973-868-2042
                      address_line_1:
                        type: string
                        example: '77432 Amber Crossing'
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: Leuschkeland
                      state:
                        type: string
                        example: Kentucky
                      postal_code:
                        type: string
                        example: '25744'
                      country:
                        type: string
                        example: MD
                      currency:
                        type: string
                        example: USD
                      payment_terms:
                        type: integer
                        example: 30
                      notes:
                        type: string
                        example: null
                        nullable: true
                      is_archived:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Client is already in this company.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Client is already in this company.'
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                target_company_id:
                  type: integer
                  description: ''
                  example: 16
              required:
                - target_company_id
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/stats':
    get:
      summary: 'Get client stats'
      operationId: getClientStats
      description: 'Returns total invoiced, total paid, outstanding balance (active invoices only), and total tracked hours for the client.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    total_invoiced: 10000
                    total_paid: 5000
                    outstanding: 5000
                    total_hours: 12.5
                properties:
                  data:
                    type: object
                    properties:
                      total_invoiced:
                        type: integer
                        example: 10000
                      total_paid:
                        type: integer
                        example: 5000
                      outstanding:
                        type: integer
                        example: 5000
                      total_hours:
                        type: number
                        example: 12.5
      tags:
        - Clients
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/statement':
    get:
      summary: 'Get client statement data'
      operationId: getClientStatementData
      description: 'Returns a list of non-draft, non-voided invoices for the date range with running balance, plus total invoiced, paid, and outstanding amounts.'
      parameters:
        -
          in: query
          name: from
          description: 'Start date (YYYY-MM-DD).'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Start date (YYYY-MM-DD).'
            example: '2026-01-01'
        -
          in: query
          name: to
          description: 'End date (YYYY-MM-DD).'
          example: '2026-03-31'
          required: false
          schema:
            type: string
            description: 'End date (YYYY-MM-DD).'
            example: '2026-03-31'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    client: {  }
                    from: '2026-01-01'
                    to: '2026-03-31'
                    total_invoiced: 10000
                    total_paid: 5000
                    total_outstanding: 5000
                    items: []
                properties:
                  data:
                    type: object
                    properties:
                      client:
                        type: object
                        properties: {  }
                      from:
                        type: string
                        example: '2026-01-01'
                      to:
                        type: string
                        example: '2026-03-31'
                      total_invoiced:
                        type: integer
                        example: 10000
                      total_paid:
                        type: integer
                        example: 5000
                      total_outstanding:
                        type: integer
                        example: 5000
                      items:
                        type: array
                        example: []
      tags:
        - Clients
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                to:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/statement/pdf':
    get:
      summary: 'Download client statement as PDF'
      operationId: downloadClientStatementAsPDF
      description: "Generates a PDF statement using the company's default invoice template and streams it as a file download."
      parameters:
        -
          in: query
          name: from
          description: 'Start date (YYYY-MM-DD).'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Start date (YYYY-MM-DD).'
            example: '2026-01-01'
        -
          in: query
          name: to
          description: 'End date (YYYY-MM-DD).'
          example: '2026-03-31'
          required: false
          schema:
            type: string
            description: 'End date (YYYY-MM-DD).'
            example: '2026-03-31'
      responses:
        200:
          description: 'PDF binary'
          content:
            application/json:
              schema:
                type: object
                example:
                  content-type: application/pdf
                properties:
                  content-type:
                    type: string
                    example: application/pdf
      tags:
        - Clients
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                to:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/statement/send':
    post:
      summary: 'Send client statement by email'
      operationId: sendClientStatementByEmail
      description: "Generates the statement PDF and emails it to the client's primary contact or email address. Accepts an optional `note` for a custom body and a `cc` list of additional recipients."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Statement sent successfully.'
                properties:
                  message:
                    type: string
                    example: 'Statement sent successfully.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Client has no email address.'
                properties:
                  message:
                    type: string
                    example: 'Client has no email address.'
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                to:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                note:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: b
                  nullable: true
                cc:
                  type: array
                  description: 'Must be a valid email address.'
                  example:
                    - zbailey@example.net
                  items:
                    type: string
              required:
                - from
                - to
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/contacts':
    get:
      summary: 'List client contacts'
      operationId: listClientContacts
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 124
                      name: 'Morgan Hirthe'
                      email: dare.emelie@example.com
                      phone: '+14324666067'
                      is_primary: false
                      created_at: '2026-04-05T19:38:15.000000Z'
                    -
                      id: 125
                      name: 'Ms. Anais Conroy'
                      email: moises37@example.com
                      phone: 1-678-926-5062
                      is_primary: false
                      created_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 124
                        name: 'Morgan Hirthe'
                        email: dare.emelie@example.com
                        phone: '+14324666067'
                        is_primary: false
                        created_at: '2026-04-05T19:38:15.000000Z'
                      -
                        id: 125
                        name: 'Ms. Anais Conroy'
                        email: moises37@example.com
                        phone: 1-678-926-5062
                        is_primary: false
                        created_at: '2026-04-05T19:38:15.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 124
                        name:
                          type: string
                          example: 'Morgan Hirthe'
                        email:
                          type: string
                          example: dare.emelie@example.com
                        phone:
                          type: string
                          example: '+14324666067'
                        is_primary:
                          type: boolean
                          example: false
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
    post:
      summary: 'Create a client contact'
      operationId: createAClientContact
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 126
                    name: 'Mr. Gerhard Dach Jr.'
                    email: lafayette.considine@example.com
                    phone: +1-626-249-0432
                    is_primary: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 126
                      name:
                        type: string
                        example: 'Mr. Gerhard Dach Jr.'
                      email:
                        type: string
                        example: lafayette.considine@example.com
                      phone:
                        type: string
                        example: +1-626-249-0432
                      is_primary:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: zbailey@example.net
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: i
                  nullable: true
                is_primary:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
              required:
                - name
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/contacts/{id}':
    get:
      summary: 'Get a client contact'
      operationId: getAClientContact
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 127
                    name: 'Morgan Hirthe'
                    email: dare.emelie@example.com
                    phone: '+14324666067'
                    is_primary: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 127
                      name:
                        type: string
                        example: 'Morgan Hirthe'
                      email:
                        type: string
                        example: dare.emelie@example.com
                      phone:
                        type: string
                        example: '+14324666067'
                      is_primary:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
    put:
      summary: 'Update a client contact'
      operationId: updateAClientContact
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 128
                    name: 'Mr. Gerhard Dach Jr.'
                    email: lafayette.considine@example.com
                    phone: +1-626-249-0432
                    is_primary: false
                    created_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 128
                      name:
                        type: string
                        example: 'Mr. Gerhard Dach Jr.'
                      email:
                        type: string
                        example: lafayette.considine@example.com
                      phone:
                        type: string
                        example: +1-626-249-0432
                      is_primary:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Clients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: zbailey@example.net
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: i
                  nullable: true
                is_primary:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
              required:
                - name
    delete:
      summary: 'Delete a client contact'
      operationId: deleteAClientContact
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Clients
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
      -
        in: path
        name: id
        description: 'The ID of the contact.'
        example: 1
        required: true
        schema:
          type: integer
  /api/invoices/bulk-action:
    post:
      summary: 'Bulk action on invoices.'
      operationId: bulkActionOnInvoices
      description: 'Supported actions: `archive`, `unarchive`, `mark-sent` (draft invoices only), `delete` (draft invoices only, also unbills linked time entries). Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: unarchive
                  enum:
                    - archive
                    - unarchive
                    - mark-sent
                    - delete
              required:
                - action
  /api/invoices/bulk-record-payment:
    post:
      summary: 'Bulk record payments for multiple invoices.'
      operationId: bulkRecordPaymentsForMultipleInvoices
      description: 'Records a payment against each invoice in a single transaction. If `send_notification` is true, a payment received email is sent to each affected client.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    recorded: 2
                    errors: []
                properties:
                  data:
                    type: object
                    properties:
                      recorded:
                        type: integer
                        example: 2
                      errors:
                        type: array
                        example: []
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                payments:
                  type: array
                  description: 'Must have at least 1 items. Must not have more than 100 items.'
                  example:
                    - []
                  items:
                    type: object
                    properties:
                      invoice_id:
                        type: integer
                        description: ''
                        example: 16
                      amount:
                        type: integer
                        description: 'Must be at least 1.'
                        example: 22
                      payment_date:
                        type: string
                        description: 'Must be a valid date.'
                        example: '2026-04-05T19:38:19'
                      payment_method:
                        type: string
                        description: 'Must not be greater than 100 characters.'
                        example: g
                        nullable: true
                      reference:
                        type: string
                        description: 'Must not be greater than 255 characters.'
                        example: z
                        nullable: true
                      notes:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: m
                        nullable: true
                    required:
                      - invoice_id
                      - amount
                      - payment_date
                send_notification:
                  type: boolean
                  description: ''
                  example: false
              required:
                - payments
  /api/invoices:
    get:
      summary: 'List invoices.'
      operationId: listInvoices
      description: 'Supports filtering by status, client_id, invoice_number, and a comma-separated ids list. Results are paginated and include aggregate totals and status counts in the meta.'
      parameters:
        -
          in: query
          name: 'filter[status]'
          description: 'Filter by status.'
          example: sent
          required: false
          schema:
            type: string
            description: 'Filter by status.'
            example: sent
        -
          in: query
          name: 'filter[client_id]'
          description: 'Filter by client ID.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by client ID.'
            example: 1
        -
          in: query
          name: 'filter[invoice_number]'
          description: 'Partial match on invoice number.'
          example: INV-001
          required: false
          schema:
            type: string
            description: 'Partial match on invoice number.'
            example: INV-001
        -
          in: query
          name: 'filter[ids]'
          description: 'Comma-separated list of invoice IDs.'
          example: '1,2,3'
          required: false
          schema:
            type: string
            description: 'Comma-separated list of invoice IDs.'
            example: '1,2,3'
        -
          in: query
          name: sort
          description: 'Sort field (prefix with - for descending).'
          example: '-issue_date'
          required: false
          schema:
            type: string
            description: 'Sort field (prefix with - for descending).'
            example: '-issue_date'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1599
                      uuid: a2dbfa6b-cc9d-4b33-96f9-0c2b607910bb
                      client_id: 155
                      recurring_invoice_id: null
                      invoice_number: INV-79198
                      status: draft
                      is_archived: false
                      status_label: Draft
                      status_color: gray
                      issue_date: '2026-04-05'
                      due_date: '2026-05-05'
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      amount_paid: 0
                      amount_due: 0
                      notes: null
                      terms: null
                      footer: null
                      sent_at: null
                      viewed_at: null
                      paid_at: null
                      late_fee_amount: 0
                      late_fee_applied_at: null
                      reminders_sent: 0
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                    -
                      id: 1600
                      uuid: 458979ce-7d33-4578-a55f-d98c55ed88f2
                      client_id: 156
                      recurring_invoice_id: null
                      invoice_number: INV-21385
                      status: draft
                      is_archived: false
                      status_label: Draft
                      status_color: gray
                      issue_date: '2026-04-05'
                      due_date: '2026-05-05'
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      amount_paid: 0
                      amount_due: 0
                      notes: null
                      terms: null
                      footer: null
                      sent_at: null
                      viewed_at: null
                      paid_at: null
                      late_fee_amount: 0
                      late_fee_applied_at: null
                      reminders_sent: 0
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1599
                        uuid: a2dbfa6b-cc9d-4b33-96f9-0c2b607910bb
                        client_id: 155
                        recurring_invoice_id: null
                        invoice_number: INV-79198
                        status: draft
                        is_archived: false
                        status_label: Draft
                        status_color: gray
                        issue_date: '2026-04-05'
                        due_date: '2026-05-05'
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        amount_paid: 0
                        amount_due: 0
                        notes: null
                        terms: null
                        footer: null
                        sent_at: null
                        viewed_at: null
                        paid_at: null
                        late_fee_amount: 0
                        late_fee_applied_at: null
                        reminders_sent: 0
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                      -
                        id: 1600
                        uuid: 458979ce-7d33-4578-a55f-d98c55ed88f2
                        client_id: 156
                        recurring_invoice_id: null
                        invoice_number: INV-21385
                        status: draft
                        is_archived: false
                        status_label: Draft
                        status_color: gray
                        issue_date: '2026-04-05'
                        due_date: '2026-05-05'
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        amount_paid: 0
                        amount_due: 0
                        notes: null
                        terms: null
                        footer: null
                        sent_at: null
                        viewed_at: null
                        paid_at: null
                        late_fee_amount: 0
                        late_fee_applied_at: null
                        reminders_sent: 0
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1599
                        uuid:
                          type: string
                          example: a2dbfa6b-cc9d-4b33-96f9-0c2b607910bb
                        client_id:
                          type: integer
                          example: 155
                        recurring_invoice_id:
                          type: string
                          example: null
                          nullable: true
                        invoice_number:
                          type: string
                          example: INV-79198
                        status:
                          type: string
                          example: draft
                        is_archived:
                          type: boolean
                          example: false
                        status_label:
                          type: string
                          example: Draft
                        status_color:
                          type: string
                          example: gray
                        issue_date:
                          type: string
                          example: '2026-04-05'
                        due_date:
                          type: string
                          example: '2026-05-05'
                        currency:
                          type: string
                          example: USD
                        subtotal:
                          type: integer
                          example: 0
                        tax_total:
                          type: integer
                          example: 0
                        discount_type:
                          type: string
                          example: null
                          nullable: true
                        discount_value:
                          type: string
                          example: null
                          nullable: true
                        discount_total:
                          type: integer
                          example: 0
                        total:
                          type: integer
                          example: 0
                        amount_paid:
                          type: integer
                          example: 0
                        amount_due:
                          type: integer
                          example: 0
                        notes:
                          type: string
                          example: null
                          nullable: true
                        terms:
                          type: string
                          example: null
                          nullable: true
                        footer:
                          type: string
                          example: null
                          nullable: true
                        sent_at:
                          type: string
                          example: null
                          nullable: true
                        viewed_at:
                          type: string
                          example: null
                          nullable: true
                        paid_at:
                          type: string
                          example: null
                          nullable: true
                        late_fee_amount:
                          type: integer
                          example: 0
                        late_fee_applied_at:
                          type: string
                          example: null
                          nullable: true
                        reminders_sent:
                          type: integer
                          example: 0
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    post:
      summary: 'Create an invoice.'
      operationId: createAnInvoice
      description: 'Creates a draft invoice. Pass a `line_items` array to create and attach line items in the same request.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1601
                    uuid: 5ce597fd-4196-459a-ac53-a97436b8c7b6
                    client_id: 157
                    recurring_invoice_id: null
                    invoice_number: INV-70546
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1601
                      uuid:
                        type: string
                        example: 5ce597fd-4196-459a-ac53-a97436b8c7b6
                      client_id:
                        type: integer
                        example: 157
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-70546
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: architecto
                issue_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:19'
                  nullable: true
                due_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>issue_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                terms:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: g
                  nullable: true
                footer:
                  type: string
                  description: 'Must not be greater than 500 characters.'
                  example: z
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
              required:
                - client_id
  '/api/invoices/{id}':
    get:
      summary: 'Get an invoice.'
      operationId: getAnInvoice
      description: 'Includes the client, all line items (including late fee items), and payment records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1602
                    uuid: 245c8ecd-a2e5-4497-85e0-fdad85549e30
                    client_id: 158
                    recurring_invoice_id: null
                    invoice_number: INV-54634
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1602
                      uuid:
                        type: string
                        example: 245c8ecd-a2e5-4497-85e0-fdad85549e30
                      client_id:
                        type: integer
                        example: 158
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-54634
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    put:
      summary: 'Update an invoice.'
      operationId: updateAnInvoice
      description: 'If `line_items` is provided, the full set of line items is synced (added, updated, and removed). Omit `line_items` to update invoice fields only without touching line items.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1603
                    uuid: 64c63ff1-396c-4f1f-a073-f1ff3c3a2184
                    client_id: 159
                    recurring_invoice_id: null
                    invoice_number: INV-63526
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1603
                      uuid:
                        type: string
                        example: 64c63ff1-396c-4f1f-a073-f1ff3c3a2184
                      client_id:
                        type: integer
                        example: 159
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-63526
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                issue_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:19'
                  nullable: true
                due_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>issue_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                terms:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: g
                  nullable: true
                footer:
                  type: string
                  description: 'Must not be greater than 500 characters.'
                  example: z
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
    delete:
      summary: 'Delete an invoice.'
      operationId: deleteAnInvoice
      description: 'Soft deletes the invoice and marks any linked time entries as unbilled so they can be re-invoiced.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/line-items':
    get:
      summary: 'List line items for an invoice.'
      operationId: listLineItemsForAnInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 10149
                      service_id: null
                      time_entry_id: null
                      description: 'Nostrum qui commodi incidunt iure.'
                      quantity: 1.02
                      unit_price: '13053.000000'
                      amount: 13314
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                    -
                      id: 10150
                      service_id: null
                      time_entry_id: null
                      description: 'Nemo voluptate accusamus ut et.'
                      quantity: 8.73
                      unit_price: '36405.000000'
                      amount: 317816
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 10149
                        service_id: null
                        time_entry_id: null
                        description: 'Nostrum qui commodi incidunt iure.'
                        quantity: 1.02
                        unit_price: '13053.000000'
                        amount: 13314
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                      -
                        id: 10150
                        service_id: null
                        time_entry_id: null
                        description: 'Nemo voluptate accusamus ut et.'
                        quantity: 8.73
                        unit_price: '36405.000000'
                        amount: 317816
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 10149
                        service_id:
                          type: string
                          example: null
                          nullable: true
                        time_entry_id:
                          type: string
                          example: null
                          nullable: true
                        description:
                          type: string
                          example: 'Nostrum qui commodi incidunt iure.'
                        quantity:
                          type: number
                          example: 1.02
                        unit_price:
                          type: string
                          example: '13053.000000'
                        amount:
                          type: integer
                          example: 13314
                        tax_name_1:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_1:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_1:
                          type: integer
                          example: 0
                        tax_name_2:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_2:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_2:
                          type: integer
                          example: 0
                        sort_order:
                          type: integer
                          example: 0
                        is_late_fee:
                          type: boolean
                          example: false
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    post:
      summary: 'Add a line item to an invoice.'
      operationId: addALineItemToAnInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 10151
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 10151
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/line-items/{lineItem_id}':
    put:
      summary: 'Update a line item on an invoice.'
      operationId: updateALineItemOnAnInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 10152
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 10152
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    delete:
      summary: 'Delete a line item from an invoice.'
      operationId: deleteALineItemFromAnInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem_id
        description: 'The ID of the lineItem.'
        example: 20
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem
        description: 'The line item ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/archive':
    post:
      summary: 'Archive an invoice.'
      operationId: archiveAnInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/unarchive':
    post:
      summary: 'Unarchive an invoice.'
      operationId: unarchiveAnInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/move':
    post:
      summary: 'Move an invoice to another company.'
      operationId: moveAnInvoiceToAnotherCompany
      description: 'The authenticated user must have access to the target company. Reassigns the invoice, its payments, credits, time entries, and expenses to the target company.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1608
                    uuid: 3ea400bd-683a-4261-a610-0afa3c801d65
                    client_id: 164
                    recurring_invoice_id: null
                    invoice_number: INV-80304
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1608
                      uuid:
                        type: string
                        example: 3ea400bd-683a-4261-a610-0afa3c801d65
                      client_id:
                        type: integer
                        example: 164
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-80304
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/import-time':
    post:
      summary: 'Import time entries as line items onto an invoice.'
      operationId: importTimeEntriesAsLineItemsOntoAnInvoice
      description: 'Converts the specified unbilled time entries into invoice line items and marks them as billed. Accepts an array of `time_entry_ids`.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1609
                    uuid: fa2ce905-7b4f-4195-afcc-00ffb631e736
                    client_id: 165
                    recurring_invoice_id: null
                    invoice_number: INV-24492
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1609
                      uuid:
                        type: string
                        example: fa2ce905-7b4f-4195-afcc-00ffb631e736
                      client_id:
                        type: integer
                        example: 165
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-24492
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                time_entry_ids:
                  type: array
                  description: 'The <code>id</code> of an existing record in the time_entries table.'
                  example:
                    - 16
                  items:
                    type: integer
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/send':
    post:
      summary: 'Send an invoice by email.'
      operationId: sendAnInvoiceByEmail
      description: "Sends the invoice to the client's email address and transitions a draft invoice to sent status. Returns 422 if the client has no email configured."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1610
                    uuid: c15f8d2e-94cf-4858-b434-429303945b48
                    client_id: 166
                    recurring_invoice_id: null
                    invoice_number: INV-14650
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1610
                      uuid:
                        type: string
                        example: c15f8d2e-94cf-4858-b434-429303945b48
                      client_id:
                        type: integer
                        example: 166
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-14650
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/mark-sent':
    post:
      summary: 'Mark an invoice as sent without emailing.'
      operationId: markAnInvoiceAsSentWithoutEmailing
      description: 'Transitions the invoice status to sent and logs the activity, but does not send any email to the client.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1611
                    uuid: 9b5f355b-edb9-48c6-863a-589f17b401ca
                    client_id: 167
                    recurring_invoice_id: null
                    invoice_number: INV-62492
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1611
                      uuid:
                        type: string
                        example: 9b5f355b-edb9-48c6-863a-589f17b401ca
                      client_id:
                        type: integer
                        example: 167
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-62492
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/mark-paid':
    post:
      summary: 'Mark an invoice as fully paid.'
      operationId: markAnInvoiceAsFullyPaid
      description: 'Sets amount_paid to the invoice total and amount_due to zero in a single transaction, then transitions the status to paid.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1612
                    uuid: 501f9d28-97c4-4bfb-b2af-1d9e6114fda7
                    client_id: 168
                    recurring_invoice_id: null
                    invoice_number: INV-45193
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1612
                      uuid:
                        type: string
                        example: 501f9d28-97c4-4bfb-b2af-1d9e6114fda7
                      client_id:
                        type: integer
                        example: 168
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-45193
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/record-payment':
    post:
      summary: 'Record a payment against an invoice.'
      operationId: recordAPaymentAgainstAnInvoice
      description: 'Records a partial or full payment and updates amount_paid and amount_due. Automatically transitions the invoice to partial or paid status based on the remaining balance.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1613
                    uuid: 8f637055-efeb-4f8b-9aaa-8e46e57b8fac
                    client_id: 169
                    recurring_invoice_id: null
                    invoice_number: INV-45117
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1613
                      uuid:
                        type: string
                        example: 8f637055-efeb-4f8b-9aaa-8e46e57b8fac
                      client_id:
                        type: integer
                        example: 169
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-45117
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: integer
                  description: 'Must be at least 1. Must not be greater than 999999999.'
                  example: 1
                payment_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:19'
                payment_method:
                  type: string
                  description: ''
                  example: card
                  enum:
                    - bank_transfer
                    - card
                    - cash
                    - cheque
                    - paypal
                    - ach
                    - 2checkout
                    - other
                  nullable: true
                reference:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: g
                  nullable: true
              required:
                - amount
                - payment_date
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/void':
    post:
      summary: 'Void an invoice.'
      operationId: voidAnInvoice
      description: 'Transitions the invoice to cancelled status and marks any linked time entries as unbilled so they can be re-invoiced.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1614
                    uuid: a712eab5-a5ad-4a1b-8496-4966297be422
                    client_id: 170
                    recurring_invoice_id: null
                    invoice_number: INV-30805
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1614
                      uuid:
                        type: string
                        example: a712eab5-a5ad-4a1b-8496-4966297be422
                      client_id:
                        type: integer
                        example: 170
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-30805
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/duplicate':
    post:
      summary: 'Duplicate an invoice.'
      operationId: duplicateAnInvoice
      description: 'Creates a new draft invoice with the same line items and client as the original, assigned the next available invoice number.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1615
                    uuid: 526b85dc-f533-4d45-85fc-ea5483106ae6
                    client_id: 171
                    recurring_invoice_id: null
                    invoice_number: INV-93082
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1615
                      uuid:
                        type: string
                        example: 526b85dc-f533-4d45-85fc-ea5483106ae6
                      client_id:
                        type: integer
                        example: 171
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-93082
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/invoices/{invoice_id}/pdf':
    get:
      summary: 'Download invoice as PDF.'
      operationId: downloadInvoiceAsPDF
      description: "Generates the invoice PDF on demand and streams it inline using the company's default template."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: invoice_id
        description: 'The ID of the invoice.'
        example: 1088
        required: true
        schema:
          type: integer
      -
        in: path
        name: invoice
        description: 'The invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  /api/quotes/bulk-action:
    post:
      summary: 'Bulk action on quotes.'
      operationId: bulkActionOnQuotes
      description: 'Supported actions: `archive`, `unarchive`, `mark-sent` (draft quotes only), `delete` (draft quotes only). Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: mark-sent
                  enum:
                    - archive
                    - unarchive
                    - mark-sent
                    - delete
              required:
                - action
  /api/quotes:
    get:
      summary: 'List quotes.'
      operationId: listQuotes
      description: 'Supports filtering by status, client_id, and quote_number. Results are paginated and include active/archived counts in the meta.'
      parameters:
        -
          in: query
          name: 'filter[status]'
          description: 'Filter by status.'
          example: sent
          required: false
          schema:
            type: string
            description: 'Filter by status.'
            example: sent
        -
          in: query
          name: 'filter[client_id]'
          description: 'Filter by client ID.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by client ID.'
            example: 1
        -
          in: query
          name: 'filter[quote_number]'
          description: 'Partial match on quote number.'
          example: QUO-001
          required: false
          schema:
            type: string
            description: 'Partial match on quote number.'
            example: QUO-001
        -
          in: query
          name: sort
          description: 'Sort field (prefix with - for descending).'
          example: '-issue_date'
          required: false
          schema:
            type: string
            description: 'Sort field (prefix with - for descending).'
            example: '-issue_date'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 154
                      uuid: 3a2924fe-1de9-4cf1-a89c-03baf0e76d42
                      client_id: 172
                      quote_number: QUO-92439
                      status: draft
                      is_archived: false
                      status_label: Draft
                      status_color: gray
                      issue_date: '2026-04-05'
                      expiry_date: '2026-05-05'
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      notes: null
                      terms: null
                      footer: null
                      sent_at: null
                      viewed_at: null
                      accepted_at: null
                      declined_at: null
                      converted_to_invoice_id: null
                      converted_to_project_id: null
                      pdf_path: null
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                    -
                      id: 155
                      uuid: 307265bb-89f7-4c75-b5e8-cc58585bbe7f
                      client_id: 173
                      quote_number: QUO-09313
                      status: draft
                      is_archived: false
                      status_label: Draft
                      status_color: gray
                      issue_date: '2026-04-05'
                      expiry_date: '2026-05-05'
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      notes: null
                      terms: null
                      footer: null
                      sent_at: null
                      viewed_at: null
                      accepted_at: null
                      declined_at: null
                      converted_to_invoice_id: null
                      converted_to_project_id: null
                      pdf_path: null
                      created_at: '2026-04-05T19:38:19.000000Z'
                      updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 154
                        uuid: 3a2924fe-1de9-4cf1-a89c-03baf0e76d42
                        client_id: 172
                        quote_number: QUO-92439
                        status: draft
                        is_archived: false
                        status_label: Draft
                        status_color: gray
                        issue_date: '2026-04-05'
                        expiry_date: '2026-05-05'
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        notes: null
                        terms: null
                        footer: null
                        sent_at: null
                        viewed_at: null
                        accepted_at: null
                        declined_at: null
                        converted_to_invoice_id: null
                        converted_to_project_id: null
                        pdf_path: null
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                      -
                        id: 155
                        uuid: 307265bb-89f7-4c75-b5e8-cc58585bbe7f
                        client_id: 173
                        quote_number: QUO-09313
                        status: draft
                        is_archived: false
                        status_label: Draft
                        status_color: gray
                        issue_date: '2026-04-05'
                        expiry_date: '2026-05-05'
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        notes: null
                        terms: null
                        footer: null
                        sent_at: null
                        viewed_at: null
                        accepted_at: null
                        declined_at: null
                        converted_to_invoice_id: null
                        converted_to_project_id: null
                        pdf_path: null
                        created_at: '2026-04-05T19:38:19.000000Z'
                        updated_at: '2026-04-05T19:38:19.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 154
                        uuid:
                          type: string
                          example: 3a2924fe-1de9-4cf1-a89c-03baf0e76d42
                        client_id:
                          type: integer
                          example: 172
                        quote_number:
                          type: string
                          example: QUO-92439
                        status:
                          type: string
                          example: draft
                        is_archived:
                          type: boolean
                          example: false
                        status_label:
                          type: string
                          example: Draft
                        status_color:
                          type: string
                          example: gray
                        issue_date:
                          type: string
                          example: '2026-04-05'
                        expiry_date:
                          type: string
                          example: '2026-05-05'
                        currency:
                          type: string
                          example: USD
                        subtotal:
                          type: integer
                          example: 0
                        tax_total:
                          type: integer
                          example: 0
                        discount_type:
                          type: string
                          example: null
                          nullable: true
                        discount_value:
                          type: string
                          example: null
                          nullable: true
                        discount_total:
                          type: integer
                          example: 0
                        total:
                          type: integer
                          example: 0
                        notes:
                          type: string
                          example: null
                          nullable: true
                        terms:
                          type: string
                          example: null
                          nullable: true
                        footer:
                          type: string
                          example: null
                          nullable: true
                        sent_at:
                          type: string
                          example: null
                          nullable: true
                        viewed_at:
                          type: string
                          example: null
                          nullable: true
                        accepted_at:
                          type: string
                          example: null
                          nullable: true
                        declined_at:
                          type: string
                          example: null
                          nullable: true
                        converted_to_invoice_id:
                          type: string
                          example: null
                          nullable: true
                        converted_to_project_id:
                          type: string
                          example: null
                          nullable: true
                        pdf_path:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:19.000000Z'
      tags:
        - Quotes
    post:
      summary: 'Create a quote.'
      operationId: createAQuote
      description: 'Creates a draft quote. Pass a `line_items` array to create and attach line items in the same request.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 156
                    uuid: 36c78c49-6db6-49a2-89b1-14e1472123d9
                    client_id: 174
                    quote_number: QUO-26855
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 156
                      uuid:
                        type: string
                        example: 36c78c49-6db6-49a2-89b1-14e1472123d9
                      client_id:
                        type: integer
                        example: 174
                      quote_number:
                        type: string
                        example: QUO-26855
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: architecto
                issue_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:19'
                  nullable: true
                expiry_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>issue_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                terms:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: g
                  nullable: true
                footer:
                  type: string
                  description: 'Must not be greater than 500 characters.'
                  example: z
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
              required:
                - client_id
  '/api/quotes/{id}':
    get:
      summary: 'Get a quote.'
      operationId: getAQuote
      description: 'Includes the client and all line items.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 157
                    uuid: 5c547376-ab85-43b3-a8d4-78a9825f8192
                    client_id: 175
                    quote_number: QUO-47352
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 157
                      uuid:
                        type: string
                        example: 5c547376-ab85-43b3-a8d4-78a9825f8192
                      client_id:
                        type: integer
                        example: 175
                      quote_number:
                        type: string
                        example: QUO-47352
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
    put:
      summary: 'Update a quote.'
      operationId: updateAQuote
      description: 'If `line_items` is provided, the full set of line items is synced. Omit `line_items` to update quote fields only without touching line items.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 158
                    uuid: be67fa0b-ce1b-4e12-b309-0ff89a74305e
                    client_id: 176
                    quote_number: QUO-23164
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 158
                      uuid:
                        type: string
                        example: be67fa0b-ce1b-4e12-b309-0ff89a74305e
                      client_id:
                        type: integer
                        example: 176
                      quote_number:
                        type: string
                        example: QUO-23164
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                issue_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:20'
                  nullable: true
                expiry_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>issue_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                terms:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: g
                  nullable: true
                footer:
                  type: string
                  description: 'Must not be greater than 500 characters.'
                  example: z
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
    delete:
      summary: 'Delete a quote.'
      operationId: deleteAQuote
      description: 'Only draft quotes can be deleted. Returns 422 for any other status.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/line-items':
    get:
      summary: 'List line items for a quote.'
      operationId: listLineItemsForAQuote
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1512
                      service_id: null
                      time_entry_id: null
                      description: 'Nostrum qui commodi incidunt iure.'
                      quantity: 1.02
                      unit_price: '13053.000000'
                      amount: 13314
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:20.000000Z'
                      updated_at: '2026-04-05T19:38:20.000000Z'
                    -
                      id: 1513
                      service_id: null
                      time_entry_id: null
                      description: 'Nemo voluptate accusamus ut et.'
                      quantity: 8.73
                      unit_price: '36405.000000'
                      amount: 317816
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:20.000000Z'
                      updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1512
                        service_id: null
                        time_entry_id: null
                        description: 'Nostrum qui commodi incidunt iure.'
                        quantity: 1.02
                        unit_price: '13053.000000'
                        amount: 13314
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:20.000000Z'
                        updated_at: '2026-04-05T19:38:20.000000Z'
                      -
                        id: 1513
                        service_id: null
                        time_entry_id: null
                        description: 'Nemo voluptate accusamus ut et.'
                        quantity: 8.73
                        unit_price: '36405.000000'
                        amount: 317816
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:20.000000Z'
                        updated_at: '2026-04-05T19:38:20.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1512
                        service_id:
                          type: string
                          example: null
                          nullable: true
                        time_entry_id:
                          type: string
                          example: null
                          nullable: true
                        description:
                          type: string
                          example: 'Nostrum qui commodi incidunt iure.'
                        quantity:
                          type: number
                          example: 1.02
                        unit_price:
                          type: string
                          example: '13053.000000'
                        amount:
                          type: integer
                          example: 13314
                        tax_name_1:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_1:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_1:
                          type: integer
                          example: 0
                        tax_name_2:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_2:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_2:
                          type: integer
                          example: 0
                        sort_order:
                          type: integer
                          example: 0
                        is_late_fee:
                          type: boolean
                          example: false
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:20.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
    post:
      summary: 'Add a line item to a quote.'
      operationId: addALineItemToAQuote
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1514
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1514
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/line-items/{lineItem_id}':
    put:
      summary: 'Update a line item on a quote.'
      operationId: updateALineItemOnAQuote
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1515
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1515
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    delete:
      summary: 'Delete a line item from a quote.'
      operationId: deleteALineItemFromAQuote
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem_id
        description: 'The ID of the lineItem.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem
        description: 'The line item ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/archive':
    post:
      summary: 'Archive a quote.'
      operationId: archiveAQuote
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/unarchive':
    post:
      summary: 'Unarchive a quote.'
      operationId: unarchiveAQuote
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/send':
    post:
      summary: 'Send a quote by email.'
      operationId: sendAQuoteByEmail
      description: "Sends the quote to the client's email address and transitions the status to sent. Returns 422 if the client has no email configured."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 163
                    uuid: f102d993-55e1-4722-9374-5c984455862a
                    client_id: 181
                    quote_number: QUO-35644
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 163
                      uuid:
                        type: string
                        example: f102d993-55e1-4722-9374-5c984455862a
                      client_id:
                        type: integer
                        example: 181
                      quote_number:
                        type: string
                        example: QUO-35644
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/mark-sent':
    post:
      summary: 'Mark a quote as sent without emailing.'
      operationId: markAQuoteAsSentWithoutEmailing
      description: 'Transitions the quote status to sent and logs the activity, but does not send any email to the client.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 164
                    uuid: 746befd7-b5a8-45fe-b63b-5a0e68a5f1d9
                    client_id: 182
                    quote_number: QUO-08317
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 164
                      uuid:
                        type: string
                        example: 746befd7-b5a8-45fe-b63b-5a0e68a5f1d9
                      client_id:
                        type: integer
                        example: 182
                      quote_number:
                        type: string
                        example: QUO-08317
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/convert-to-invoice':
    post:
      summary: 'Convert a quote to an invoice.'
      operationId: convertAQuoteToAnInvoice
      description: "Creates a new draft invoice from the quote's line items and client. The quote must be in sent, viewed, or accepted status."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1616
                    uuid: 91cb4b60-aff6-4487-b436-46de2e36ed56
                    client_id: 183
                    recurring_invoice_id: null
                    invoice_number: INV-98251
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1616
                      uuid:
                        type: string
                        example: 91cb4b60-aff6-4487-b436-46de2e36ed56
                      client_id:
                        type: integer
                        example: 183
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-98251
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/convert-to-project':
    post:
      summary: 'Convert a quote to a project.'
      operationId: convertAQuoteToAProject
      description: 'Creates a new project from the quote details. The quote must be in sent, viewed, or accepted status.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 43
                    client_id: 184
                    name: 'implement intuitive e-tailers'
                    status: active
                    is_archived: false
                    billing_method: hourly
                    hourly_rate: 14351
                    budget_hours: null
                    budget_amount: null
                    start_date: null
                    end_date: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 43
                      client_id:
                        type: integer
                        example: 184
                      name:
                        type: string
                        example: 'implement intuitive e-tailers'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      billing_method:
                        type: string
                        example: hourly
                      hourly_rate:
                        type: integer
                        example: 14351
                      budget_hours:
                        type: string
                        example: null
                        nullable: true
                      budget_amount:
                        type: string
                        example: null
                        nullable: true
                      start_date:
                        type: string
                        example: null
                        nullable: true
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/duplicate':
    post:
      summary: 'Duplicate a quote.'
      operationId: duplicateAQuote
      description: 'Creates a new draft quote with the same line items and client as the original, assigned the next available quote number.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 165
                    uuid: 4b5d9dda-6611-407e-8472-ad4f39c91403
                    client_id: 185
                    quote_number: QUO-82093
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:20.000000Z'
                    updated_at: '2026-04-05T19:38:20.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 165
                      uuid:
                        type: string
                        example: 4b5d9dda-6611-407e-8472-ad4f39c91403
                      client_id:
                        type: integer
                        example: 185
                      quote_number:
                        type: string
                        example: QUO-82093
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:20.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/quotes/{quote_id}/pdf':
    get:
      summary: 'Download quote as PDF.'
      operationId: downloadQuoteAsPDF
      description: "Generates the quote PDF on demand and streams it inline using the company's default template."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
      tags:
        - Quotes
    parameters:
      -
        in: path
        name: quote_id
        description: 'The ID of the quote.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: quote
        description: 'The quote ID.'
        example: 1
        required: true
        schema:
          type: integer
  /api/projects/bulk-action:
    post:
      summary: 'Bulk action on projects.'
      operationId: bulkActionOnProjects
      description: 'Supported actions: `archive`, `unarchive`, `complete`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: archive
                  enum:
                    - archive
                    - unarchive
                    - complete
                    - delete
              required:
                - action
  /api/projects:
    get:
      summary: 'List projects.'
      operationId: listProjects
      description: 'Supports filtering by status, client_id, and name search. Results are paginated and include per-status and archived counts in the meta.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 37
                      client_id: 139
                      name: 'implement intuitive e-tailers'
                      status: active
                      is_archived: false
                      billing_method: hourly
                      hourly_rate: 14351
                      budget_hours: null
                      budget_amount: null
                      start_date: null
                      end_date: null
                      created_at: '2026-04-05T19:38:15.000000Z'
                      updated_at: '2026-04-05T19:38:15.000000Z'
                    -
                      id: 38
                      client_id: 140
                      name: 'benchmark one-to-one infrastructures'
                      status: active
                      is_archived: false
                      billing_method: hourly
                      hourly_rate: 21548
                      budget_hours: null
                      budget_amount: null
                      start_date: null
                      end_date: null
                      created_at: '2026-04-05T19:38:15.000000Z'
                      updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 37
                        client_id: 139
                        name: 'implement intuitive e-tailers'
                        status: active
                        is_archived: false
                        billing_method: hourly
                        hourly_rate: 14351
                        budget_hours: null
                        budget_amount: null
                        start_date: null
                        end_date: null
                        created_at: '2026-04-05T19:38:15.000000Z'
                        updated_at: '2026-04-05T19:38:15.000000Z'
                      -
                        id: 38
                        client_id: 140
                        name: 'benchmark one-to-one infrastructures'
                        status: active
                        is_archived: false
                        billing_method: hourly
                        hourly_rate: 21548
                        budget_hours: null
                        budget_amount: null
                        start_date: null
                        end_date: null
                        created_at: '2026-04-05T19:38:15.000000Z'
                        updated_at: '2026-04-05T19:38:15.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 37
                        client_id:
                          type: integer
                          example: 139
                        name:
                          type: string
                          example: 'implement intuitive e-tailers'
                        status:
                          type: string
                          example: active
                        is_archived:
                          type: boolean
                          example: false
                        billing_method:
                          type: string
                          example: hourly
                        hourly_rate:
                          type: integer
                          example: 14351
                        budget_hours:
                          type: string
                          example: null
                          nullable: true
                        budget_amount:
                          type: string
                          example: null
                          nullable: true
                        start_date:
                          type: string
                          example: null
                          nullable: true
                        end_date:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:15.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Projects
    post:
      summary: 'Create a project.'
      operationId: createAProject
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 39
                    client_id: 141
                    name: 'exploit scalable supply-chains'
                    status: active
                    is_archived: false
                    billing_method: hourly
                    hourly_rate: 17320
                    budget_hours: null
                    budget_amount: null
                    start_date: null
                    end_date: null
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 39
                      client_id:
                        type: integer
                        example: 141
                      name:
                        type: string
                        example: 'exploit scalable supply-chains'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      billing_method:
                        type: string
                        example: hourly
                      hourly_rate:
                        type: integer
                        example: 17320
                      budget_hours:
                        type: string
                        example: null
                        nullable: true
                      budget_amount:
                        type: string
                        example: null
                        nullable: true
                      start_date:
                        type: string
                        example: null
                        nullable: true
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: architecto
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                status:
                  type: string
                  description: ''
                  example: active
                  enum:
                    - active
                    - completed
                    - archived
                  nullable: true
                billing_method:
                  type: string
                  description: ''
                  example: flat_rate
                  enum:
                    - hourly
                    - flat_rate
                    - non_billable
                  nullable: true
                hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
                budget_hours:
                  type: number
                  description: 'Must be at least 0.'
                  example: 12
                  nullable: true
                budget_amount:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 77
                  nullable: true
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                  nullable: true
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
              required:
                - client_id
                - name
  '/api/projects/{id}':
    get:
      summary: 'Get a project.'
      operationId: getAProject
      description: 'Includes the client and project members with their hourly rates.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 40
                    client_id: 142
                    name: 'implement intuitive e-tailers'
                    status: active
                    is_archived: false
                    billing_method: hourly
                    hourly_rate: 14351
                    budget_hours: null
                    budget_amount: null
                    start_date: null
                    end_date: null
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 40
                      client_id:
                        type: integer
                        example: 142
                      name:
                        type: string
                        example: 'implement intuitive e-tailers'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      billing_method:
                        type: string
                        example: hourly
                      hourly_rate:
                        type: integer
                        example: 14351
                      budget_hours:
                        type: string
                        example: null
                        nullable: true
                      budget_amount:
                        type: string
                        example: null
                        nullable: true
                      start_date:
                        type: string
                        example: null
                        nullable: true
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Projects
    put:
      summary: 'Update a project.'
      operationId: updateAProject
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 41
                    client_id: 143
                    name: 'exploit scalable supply-chains'
                    status: active
                    is_archived: false
                    billing_method: hourly
                    hourly_rate: 17320
                    budget_hours: null
                    budget_amount: null
                    start_date: null
                    end_date: null
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 41
                      client_id:
                        type: integer
                        example: 143
                      name:
                        type: string
                        example: 'exploit scalable supply-chains'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      billing_method:
                        type: string
                        example: hourly
                      hourly_rate:
                        type: integer
                        example: 17320
                      budget_hours:
                        type: string
                        example: null
                        nullable: true
                      budget_amount:
                        type: string
                        example: null
                        nullable: true
                      start_date:
                        type: string
                        example: null
                        nullable: true
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Projects
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                status:
                  type: string
                  description: ''
                  example: archived
                  enum:
                    - active
                    - completed
                    - archived
                  nullable: true
                billing_method:
                  type: string
                  description: ''
                  example: flat_rate
                  enum:
                    - hourly
                    - flat_rate
                    - non_billable
                  nullable: true
                hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 39
                  nullable: true
                budget_hours:
                  type: number
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
                budget_amount:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 12
                  nullable: true
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:15'
                  nullable: true
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                is_archived:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
    delete:
      summary: 'Delete a project.'
      operationId: deleteAProject
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Projects
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/move':
    post:
      summary: 'Move project to another company.'
      operationId: moveProjectToAnotherCompany
      description: "Moves the project (and its time entries) to a company the authenticated user has access to.\nDetaches all project members and clears the client association."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 42
                    client_id: 144
                    name: 'exploit scalable supply-chains'
                    status: active
                    is_archived: false
                    billing_method: hourly
                    hourly_rate: 17320
                    budget_hours: null
                    budget_amount: null
                    start_date: null
                    end_date: null
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 42
                      client_id:
                        type: integer
                        example: 144
                      name:
                        type: string
                        example: 'exploit scalable supply-chains'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      billing_method:
                        type: string
                        example: hourly
                      hourly_rate:
                        type: integer
                        example: 17320
                      budget_hours:
                        type: string
                        example: null
                        nullable: true
                      budget_amount:
                        type: string
                        example: null
                        nullable: true
                      start_date:
                        type: string
                        example: null
                        nullable: true
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                target_company_id:
                  type: integer
                  description: ''
                  example: 16
              required:
                - target_company_id
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/archive':
    post:
      summary: 'Archive a project.'
      operationId: archiveAProject
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Projects
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/unarchive':
    post:
      summary: 'Unarchive a project.'
      operationId: unarchiveAProject
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Projects
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/stats':
    get:
      summary: 'Get project stats.'
      operationId: getProjectStats
      description: 'Returns hours breakdown (total, billed, unbilled) and budget info for the project.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    total_hours: 10.5
                    billed_hours: 4.0
                    unbilled_hours: 6.5
                    budget_hours: 20.0
                    budget_amount: 300000
                properties:
                  data:
                    type: object
                    properties:
                      total_hours:
                        type: number
                        example: 10.5
                      billed_hours:
                        type: number
                        example: 4.0
                      unbilled_hours:
                        type: number
                        example: 6.5
                      budget_hours:
                        type: number
                        example: 20.0
                      budget_amount:
                        type: integer
                        example: 300000
      tags:
        - Projects
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/members':
    get:
      summary: 'List project members.'
      operationId: listProjectMembers
      description: "Returns each member's user details and their project-specific hourly rate from the pivot table."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      name: 'Jane Smith'
                      email: jane@example.com
                      hourly_rate: 15000
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        name: 'Jane Smith'
                        email: jane@example.com
                        hourly_rate: 15000
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: 'Jane Smith'
                        email:
                          type: string
                          example: jane@example.com
                        hourly_rate:
                          type: integer
                          example: 15000
      tags:
        - Projects
    post:
      summary: 'Add a project member.'
      operationId: addAProjectMember
      description: 'The user must be a member of the current company. Accepts an optional `hourly_rate` (in cents) to override the company default for this project.'
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Member added.'
                properties:
                  message:
                    type: string
                    example: 'Member added.'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                user_id:
                  type: integer
                  description: ''
                  example: 16
                hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 39
                  nullable: true
              required:
                - user_id
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
  '/api/projects/{project_id}/members/{user_id}':
    delete:
      summary: 'Remove a project member.'
      operationId: removeAProjectMember
      description: 'Detaches the user from the project. The user must be a member of the current company.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Projects
    parameters:
      -
        in: path
        name: project_id
        description: 'The ID of the project.'
        example: 7
        required: true
        schema:
          type: integer
      -
        in: path
        name: user_id
        description: 'The ID of the user.'
        example: 2
        required: true
        schema:
          type: integer
  /api/time-entries/resolve-rate:
    get:
      summary: 'Resolve hourly rate.'
      operationId: resolveHourlyRate
      description: "Returns the hourly rate that would be auto-applied for a given project/service combination.\nResolution order: project rate, service rate, company default rate."
      parameters:
        -
          in: query
          name: project_id
          description: 'optional The project ID to check.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'optional The project ID to check.'
            example: 1
        -
          in: query
          name: service_id
          description: 'optional The service ID to check.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'optional The service ID to check.'
            example: 1
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  rate: 15000
                  source: project
                properties:
                  rate:
                    type: integer
                    example: 15000
                  source:
                    type: string
                    example: project
      tags:
        - 'Time Tracking'
  /api/time-entries/unbilled:
    get:
      summary: 'List unbilled time entries.'
      operationId: listUnbilledTimeEntries
      description: 'Returns billable entries that have not yet been added to an invoice. Excludes running timers.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 4818
                      user_id: 10
                      client_id: 145
                      project_id: null
                      service_id: null
                      date: '2026-03-11'
                      duration: 5783
                      started_at: null
                      ended_at: null
                      is_running: false
                      is_billable: true
                      is_billed: false
                      invoice_id: null
                      hourly_rate: 15266
                      notes: 'Qui commodi incidunt iure odit.'
                      calculated_amount: 24523
                      duration_hours: 1.61
                      created_at: '2026-04-05T19:38:16.000000Z'
                      updated_at: '2026-04-05T19:38:16.000000Z'
                    -
                      id: 4819
                      user_id: 11
                      client_id: 146
                      project_id: null
                      service_id: null
                      date: '2026-03-30'
                      duration: 17654
                      started_at: null
                      ended_at: null
                      is_running: false
                      is_billable: true
                      is_billed: false
                      invoice_id: null
                      hourly_rate: 5977
                      notes: 'Ex repellendus assumenda et tenetur ab reiciendis.'
                      calculated_amount: 29311
                      duration_hours: 4.9
                      created_at: '2026-04-05T19:38:16.000000Z'
                      updated_at: '2026-04-05T19:38:16.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 4818
                        user_id: 10
                        client_id: 145
                        project_id: null
                        service_id: null
                        date: '2026-03-11'
                        duration: 5783
                        started_at: null
                        ended_at: null
                        is_running: false
                        is_billable: true
                        is_billed: false
                        invoice_id: null
                        hourly_rate: 15266
                        notes: 'Qui commodi incidunt iure odit.'
                        calculated_amount: 24523
                        duration_hours: 1.61
                        created_at: '2026-04-05T19:38:16.000000Z'
                        updated_at: '2026-04-05T19:38:16.000000Z'
                      -
                        id: 4819
                        user_id: 11
                        client_id: 146
                        project_id: null
                        service_id: null
                        date: '2026-03-30'
                        duration: 17654
                        started_at: null
                        ended_at: null
                        is_running: false
                        is_billable: true
                        is_billed: false
                        invoice_id: null
                        hourly_rate: 5977
                        notes: 'Ex repellendus assumenda et tenetur ab reiciendis.'
                        calculated_amount: 29311
                        duration_hours: 4.9
                        created_at: '2026-04-05T19:38:16.000000Z'
                        updated_at: '2026-04-05T19:38:16.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 4818
                        user_id:
                          type: integer
                          example: 10
                        client_id:
                          type: integer
                          example: 145
                        project_id:
                          type: string
                          example: null
                          nullable: true
                        service_id:
                          type: string
                          example: null
                          nullable: true
                        date:
                          type: string
                          example: '2026-03-11'
                        duration:
                          type: integer
                          example: 5783
                        started_at:
                          type: string
                          example: null
                          nullable: true
                        ended_at:
                          type: string
                          example: null
                          nullable: true
                        is_running:
                          type: boolean
                          example: false
                        is_billable:
                          type: boolean
                          example: true
                        is_billed:
                          type: boolean
                          example: false
                        invoice_id:
                          type: string
                          example: null
                          nullable: true
                        hourly_rate:
                          type: integer
                          example: 15266
                        notes:
                          type: string
                          example: 'Qui commodi incidunt iure odit.'
                        calculated_amount:
                          type: integer
                          example: 24523
                        duration_hours:
                          type: number
                          example: 1.61
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:16.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:16.000000Z'
      tags:
        - 'Time Tracking'
  /api/time-entries/bulk:
    post:
      summary: 'Bulk create time entries.'
      operationId: bulkCreateTimeEntries
      description: 'Create up to 50 time entries in a single request. Each entry uses the same schema as the single create endpoint.'
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data: []
                properties:
                  data:
                    type: array
                    example: []
      tags:
        - 'Time Tracking'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                entries:
                  type: array
                  description: 'Array of time entry objects (max 50).'
                  example:
                    - []
                  items:
                    type: object
                    properties:
                      client_id:
                        type: integer
                        description: 'optional The client ID.'
                        example: 1
                        nullable: true
                      project_id:
                        type: integer
                        description: 'The project ID.'
                        example: 1
                      service_id:
                        type: integer
                        description: 'The service ID.'
                        example: 1
                      date:
                        type: string
                        description: 'The date of the work.'
                        example: '2026-03-29'
                      duration:
                        type: integer
                        description: 'Duration in seconds.'
                        example: 3600
                      is_billable:
                        type: boolean
                        description: 'optional Whether billable.'
                        example: true
                        nullable: true
                      hourly_rate:
                        type: integer
                        description: 'optional Hourly rate in cents.'
                        example: 15000
                        nullable: true
                      notes:
                        type: string
                        description: 'optional Description of work.'
                        example: 'API integration work'
                        nullable: true
                    required:
                      - project_id
                      - service_id
                      - date
                      - duration
              required:
                - entries
    delete:
      summary: 'Bulk delete time entries.'
      operationId: bulkDeleteTimeEntries
      description: 'Delete up to 100 time entries. Only deletes entries owned by the authenticated user.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Time Tracking'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: 'Array of time entry IDs to delete (max 100).'
                  example:
                    - 1
                    - 2
                    - 3
                  items:
                    type: integer
              required:
                - ids
  /api/time-entries:
    get:
      summary: 'List time entries.'
      operationId: listTimeEntries
      description: 'Returns a paginated list of time entries, sorted by date descending by default.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 4820
                      user_id: 12
                      client_id: 147
                      project_id: null
                      service_id: null
                      date: '2026-03-11'
                      duration: 5783
                      started_at: null
                      ended_at: null
                      is_running: false
                      is_billable: true
                      is_billed: false
                      invoice_id: null
                      hourly_rate: 15266
                      notes: 'Qui commodi incidunt iure odit.'
                      calculated_amount: 24523
                      duration_hours: 1.61
                      created_at: '2026-04-05T19:38:16.000000Z'
                      updated_at: '2026-04-05T19:38:16.000000Z'
                    -
                      id: 4821
                      user_id: 13
                      client_id: 148
                      project_id: null
                      service_id: null
                      date: '2026-03-12'
                      duration: 21598
                      started_at: null
                      ended_at: null
                      is_running: false
                      is_billable: true
                      is_billed: false
                      invoice_id: null
                      hourly_rate: 12880
                      notes: 'Repellendus assumenda et tenetur ab reiciendis.'
                      calculated_amount: 77273
                      duration_hours: 6
                      created_at: '2026-04-05T19:38:17.000000Z'
                      updated_at: '2026-04-05T19:38:17.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 4820
                        user_id: 12
                        client_id: 147
                        project_id: null
                        service_id: null
                        date: '2026-03-11'
                        duration: 5783
                        started_at: null
                        ended_at: null
                        is_running: false
                        is_billable: true
                        is_billed: false
                        invoice_id: null
                        hourly_rate: 15266
                        notes: 'Qui commodi incidunt iure odit.'
                        calculated_amount: 24523
                        duration_hours: 1.61
                        created_at: '2026-04-05T19:38:16.000000Z'
                        updated_at: '2026-04-05T19:38:16.000000Z'
                      -
                        id: 4821
                        user_id: 13
                        client_id: 148
                        project_id: null
                        service_id: null
                        date: '2026-03-12'
                        duration: 21598
                        started_at: null
                        ended_at: null
                        is_running: false
                        is_billable: true
                        is_billed: false
                        invoice_id: null
                        hourly_rate: 12880
                        notes: 'Repellendus assumenda et tenetur ab reiciendis.'
                        calculated_amount: 77273
                        duration_hours: 6
                        created_at: '2026-04-05T19:38:17.000000Z'
                        updated_at: '2026-04-05T19:38:17.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 4820
                        user_id:
                          type: integer
                          example: 12
                        client_id:
                          type: integer
                          example: 147
                        project_id:
                          type: string
                          example: null
                          nullable: true
                        service_id:
                          type: string
                          example: null
                          nullable: true
                        date:
                          type: string
                          example: '2026-03-11'
                        duration:
                          type: integer
                          example: 5783
                        started_at:
                          type: string
                          example: null
                          nullable: true
                        ended_at:
                          type: string
                          example: null
                          nullable: true
                        is_running:
                          type: boolean
                          example: false
                        is_billable:
                          type: boolean
                          example: true
                        is_billed:
                          type: boolean
                          example: false
                        invoice_id:
                          type: string
                          example: null
                          nullable: true
                        hourly_rate:
                          type: integer
                          example: 15266
                        notes:
                          type: string
                          example: 'Qui commodi incidunt iure odit.'
                        calculated_amount:
                          type: integer
                          example: 24523
                        duration_hours:
                          type: number
                          example: 1.61
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:16.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:16.000000Z'
      tags:
        - 'Time Tracking'
    post:
      summary: 'Create a time entry.'
      operationId: createATimeEntry
      description: "Create a manual time entry. Provide `date` (YYYY-MM-DD) and `duration` (in seconds, e.g. 3600 = 1 hour).\nDo NOT send `started_at`, `ended_at`, or `is_running` - those are managed by the Timer endpoints.\nIf `hourly_rate` is omitted, it is auto-resolved from the project, service, or company default rate."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4822
                    user_id: 14
                    client_id: 149
                    project_id: null
                    service_id: null
                    date: '2026-03-16'
                    duration: 1838
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 14575
                    notes: 'Sunt nihil accusantium harum mollitia.'
                    calculated_amount: 7441
                    duration_hours: 0.51
                    created_at: '2026-04-05T19:38:17.000000Z'
                    updated_at: '2026-04-05T19:38:17.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4822
                      user_id:
                        type: integer
                        example: 14
                      client_id:
                        type: integer
                        example: 149
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-03-16'
                      duration:
                        type: integer
                        example: 1838
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 14575
                      notes:
                        type: string
                        example: 'Sunt nihil accusantium harum mollitia.'
                      calculated_amount:
                        type: integer
                        example: 7441
                      duration_hours:
                        type: number
                        example: 0.51
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
      tags:
        - 'Time Tracking'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: integer
                  description: 'optional The client ID.'
                  example: 1
                  nullable: true
                project_id:
                  type: integer
                  description: 'The project ID.'
                  example: 1
                service_id:
                  type: integer
                  description: 'The service ID.'
                  example: 1
                date:
                  type: string
                  description: 'The date of the work.'
                  example: '2026-03-29'
                duration:
                  type: integer
                  description: 'Duration in seconds (e.g. 3600 = 1 hour).'
                  example: 3600
                is_billable:
                  type: boolean
                  description: 'optional Whether the entry is billable. Defaults to true.'
                  example: true
                  nullable: true
                is_billed:
                  type: boolean
                  description: 'optional Whether the entry has been billed. Defaults to false.'
                  example: false
                  nullable: true
                hourly_rate:
                  type: integer
                  description: 'optional Hourly rate in cents. Auto-resolved if omitted.'
                  example: 15000
                  nullable: true
                notes:
                  type: string
                  description: 'optional Description of work performed.'
                  example: 'API integration work'
                  nullable: true
              required:
                - project_id
                - service_id
                - date
                - duration
  '/api/time-entries/{id}':
    get:
      summary: 'Get a time entry.'
      operationId: getATimeEntry
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4823
                    user_id: 15
                    client_id: 150
                    project_id: null
                    service_id: null
                    date: '2026-03-11'
                    duration: 5783
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 15266
                    notes: 'Qui commodi incidunt iure odit.'
                    calculated_amount: 24523
                    duration_hours: 1.61
                    created_at: '2026-04-05T19:38:17.000000Z'
                    updated_at: '2026-04-05T19:38:17.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4823
                      user_id:
                        type: integer
                        example: 15
                      client_id:
                        type: integer
                        example: 150
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-03-11'
                      duration:
                        type: integer
                        example: 5783
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 15266
                      notes:
                        type: string
                        example: 'Qui commodi incidunt iure odit.'
                      calculated_amount:
                        type: integer
                        example: 24523
                      duration_hours:
                        type: number
                        example: 1.61
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
      tags:
        - 'Time Tracking'
    put:
      summary: 'Update a time entry.'
      operationId: updateATimeEntry
      description: 'Same body schema as create. Only the entry owner or a company admin/owner can update.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4824
                    user_id: 16
                    client_id: 151
                    project_id: null
                    service_id: null
                    date: '2026-03-16'
                    duration: 1838
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 14575
                    notes: 'Sunt nihil accusantium harum mollitia.'
                    calculated_amount: 7441
                    duration_hours: 0.51
                    created_at: '2026-04-05T19:38:17.000000Z'
                    updated_at: '2026-04-05T19:38:17.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4824
                      user_id:
                        type: integer
                        example: 16
                      client_id:
                        type: integer
                        example: 151
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-03-16'
                      duration:
                        type: integer
                        example: 1838
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 14575
                      notes:
                        type: string
                        example: 'Sunt nihil accusantium harum mollitia.'
                      calculated_amount:
                        type: integer
                        example: 7441
                      duration_hours:
                        type: number
                        example: 0.51
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:17.000000Z'
      tags:
        - 'Time Tracking'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                  nullable: true
                project_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the projects table.'
                  example: architecto
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: architecto
                date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:17'
                duration:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 39
                is_billable:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                is_billed:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: z
                  nullable: true
              required:
                - project_id
                - service_id
                - date
                - duration
    delete:
      summary: 'Delete a time entry.'
      operationId: deleteATimeEntry
      description: 'Only the entry owner or a company admin/owner can delete.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Time Tracking'
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the time entry.'
        example: 5
        required: true
        schema:
          type: integer
  /api/timer/start:
    post:
      summary: 'Start a timer.'
      operationId: startATimer
      description: "Starts a new running timer. If a timer is already running, it is stopped first.\nThe `started_at` is set to the current time. Duration is calculated when the timer is stopped."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4825
                    user_id: 17
                    client_id: 152
                    project_id: null
                    service_id: null
                    date: '2026-04-01'
                    duration: 21771
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 15990
                    notes: 'Et fugiat sunt nihil accusantium.'
                    calculated_amount: 96700
                    duration_hours: 6.05
                    created_at: '2026-04-05T19:38:18.000000Z'
                    updated_at: '2026-04-05T19:38:18.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4825
                      user_id:
                        type: integer
                        example: 17
                      client_id:
                        type: integer
                        example: 152
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-04-01'
                      duration:
                        type: integer
                        example: 21771
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 15990
                      notes:
                        type: string
                        example: 'Et fugiat sunt nihil accusantium.'
                      calculated_amount:
                        type: integer
                        example: 96700
                      duration_hours:
                        type: number
                        example: 6.05
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:18.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:18.000000Z'
      tags:
        - 'Time Tracking'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: integer
                  description: 'optional The client ID.'
                  example: 1
                  nullable: true
                project_id:
                  type: integer
                  description: 'optional The project ID.'
                  example: 1
                  nullable: true
                service_id:
                  type: integer
                  description: 'optional The service ID.'
                  example: 1
                  nullable: true
                notes:
                  type: string
                  description: 'optional Description of work.'
                  example: 'Working on API integration'
                  nullable: true
                is_billable:
                  type: boolean
                  description: 'optional Whether billable. Defaults to true.'
                  example: true
                  nullable: true
                hourly_rate:
                  type: integer
                  description: 'optional Hourly rate in cents. Auto-resolved if omitted.'
                  example: 15000
                  nullable: true
  /api/timer/stop:
    put:
      summary: 'Stop the running timer.'
      operationId: stopTheRunningTimer
      description: "Stops the current user's running timer, calculates the duration from `started_at` to now,\nand sets `ended_at`. Returns 404 if no timer is running."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4826
                    user_id: 18
                    client_id: 153
                    project_id: null
                    service_id: null
                    date: '2026-03-11'
                    duration: 5783
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 15266
                    notes: 'Qui commodi incidunt iure odit.'
                    calculated_amount: 24523
                    duration_hours: 1.61
                    created_at: '2026-04-05T19:38:18.000000Z'
                    updated_at: '2026-04-05T19:38:18.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4826
                      user_id:
                        type: integer
                        example: 18
                      client_id:
                        type: integer
                        example: 153
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-03-11'
                      duration:
                        type: integer
                        example: 5783
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 15266
                      notes:
                        type: string
                        example: 'Qui commodi incidunt iure odit.'
                      calculated_amount:
                        type: integer
                        example: 24523
                      duration_hours:
                        type: number
                        example: 1.61
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:18.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:18.000000Z'
      tags:
        - 'Time Tracking'
  /api/timer/current:
    get:
      summary: 'Get current running timer.'
      operationId: getCurrentRunningTimer
      description: 'Returns the current user''s running timer, or `{"data": null}` if no timer is running.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4827
                    user_id: 19
                    client_id: 154
                    project_id: null
                    service_id: null
                    date: '2026-03-11'
                    duration: 5783
                    started_at: null
                    ended_at: null
                    is_running: false
                    is_billable: true
                    is_billed: false
                    invoice_id: null
                    hourly_rate: 15266
                    notes: 'Qui commodi incidunt iure odit.'
                    calculated_amount: 24523
                    duration_hours: 1.61
                    created_at: '2026-04-05T19:38:19.000000Z'
                    updated_at: '2026-04-05T19:38:19.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4827
                      user_id:
                        type: integer
                        example: 19
                      client_id:
                        type: integer
                        example: 154
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      date:
                        type: string
                        example: '2026-03-11'
                      duration:
                        type: integer
                        example: 5783
                      started_at:
                        type: string
                        example: null
                        nullable: true
                      ended_at:
                        type: string
                        example: null
                        nullable: true
                      is_running:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: true
                      is_billed:
                        type: boolean
                        example: false
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      hourly_rate:
                        type: integer
                        example: 15266
                      notes:
                        type: string
                        example: 'Qui commodi incidunt iure odit.'
                      calculated_amount:
                        type: integer
                        example: 24523
                      duration_hours:
                        type: number
                        example: 1.61
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:19.000000Z'
      tags:
        - 'Time Tracking'
  /api/timer/discard:
    delete:
      summary: 'Discard the running timer.'
      operationId: discardTheRunningTimer
      description: 'Deletes the running timer without saving. Returns 204 whether or not a timer was running.'
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Time Tracking'
  /api/services/bulk-action:
    post:
      summary: 'Bulk action on services.'
      operationId: bulkActionOnServices
      description: 'Supported actions: `activate`, `deactivate`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Services
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: deactivate
                  enum:
                    - activate
                    - deactivate
                    - delete
              required:
                - action
  /api/services:
    get:
      summary: 'List services.'
      operationId: listServices
      description: 'Supports filtering by is_active, type, and name search. Results are paginated with active/inactive counts in the meta.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 71
                      type: service
                      name: Development
                      description: 'Quidem nostrum qui commodi incidunt iure odit.'
                      default_rate: 14003
                      unit: hour
                      tax_name_1: null
                      tax_rate_1: null
                      tax_name_2: null
                      tax_rate_2: null
                      is_active: true
                      created_at: '2026-04-05T19:38:15.000000Z'
                      updated_at: '2026-04-05T19:38:15.000000Z'
                    -
                      id: 72
                      type: service
                      name: Consulting
                      description: 'Facere tempora ex voluptatem laboriosam.'
                      default_rate: 14572
                      unit: item
                      tax_name_1: null
                      tax_rate_1: null
                      tax_name_2: null
                      tax_rate_2: null
                      is_active: true
                      created_at: '2026-04-05T19:38:15.000000Z'
                      updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 71
                        type: service
                        name: Development
                        description: 'Quidem nostrum qui commodi incidunt iure odit.'
                        default_rate: 14003
                        unit: hour
                        tax_name_1: null
                        tax_rate_1: null
                        tax_name_2: null
                        tax_rate_2: null
                        is_active: true
                        created_at: '2026-04-05T19:38:15.000000Z'
                        updated_at: '2026-04-05T19:38:15.000000Z'
                      -
                        id: 72
                        type: service
                        name: Consulting
                        description: 'Facere tempora ex voluptatem laboriosam.'
                        default_rate: 14572
                        unit: item
                        tax_name_1: null
                        tax_rate_1: null
                        tax_name_2: null
                        tax_rate_2: null
                        is_active: true
                        created_at: '2026-04-05T19:38:15.000000Z'
                        updated_at: '2026-04-05T19:38:15.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 71
                        type:
                          type: string
                          example: service
                        name:
                          type: string
                          example: Development
                        description:
                          type: string
                          example: 'Quidem nostrum qui commodi incidunt iure odit.'
                        default_rate:
                          type: integer
                          example: 14003
                        unit:
                          type: string
                          example: hour
                        tax_name_1:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_1:
                          type: string
                          example: null
                          nullable: true
                        tax_name_2:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_2:
                          type: string
                          example: null
                          nullable: true
                        is_active:
                          type: boolean
                          example: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:15.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Services
    post:
      summary: 'Create a service.'
      operationId: createAService
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 73
                    type: service
                    name: Consulting
                    description: 'Et et modi ipsum nostrum.'
                    default_rate: 13789
                    unit: day
                    tax_name_1: null
                    tax_rate_1: null
                    tax_name_2: null
                    tax_rate_2: null
                    is_active: true
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 73
                      type:
                        type: string
                        example: service
                      name:
                        type: string
                        example: Consulting
                      description:
                        type: string
                        example: 'Et et modi ipsum nostrum.'
                      default_rate:
                        type: integer
                        example: 13789
                      unit:
                        type: string
                        example: day
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      is_active:
                        type: boolean
                        example: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Services
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                description:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'Et animi quos velit et fugiat.'
                  nullable: true
                default_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 42
                  nullable: true
                type:
                  type: string
                  description: ''
                  example: product
                  enum:
                    - service
                    - product
                  nullable: true
                unit:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: ljnikhwaykcmyuwp
                  nullable: true
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: w
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 89
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: v
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 3
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
              required:
                - name
  '/api/services/{id}':
    get:
      summary: 'Get a service.'
      operationId: getAService
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 74
                    type: service
                    name: Development
                    description: 'Quidem nostrum qui commodi incidunt iure odit.'
                    default_rate: 14003
                    unit: hour
                    tax_name_1: null
                    tax_rate_1: null
                    tax_name_2: null
                    tax_rate_2: null
                    is_active: true
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 74
                      type:
                        type: string
                        example: service
                      name:
                        type: string
                        example: Development
                      description:
                        type: string
                        example: 'Quidem nostrum qui commodi incidunt iure odit.'
                      default_rate:
                        type: integer
                        example: 14003
                      unit:
                        type: string
                        example: hour
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      is_active:
                        type: boolean
                        example: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Services
    put:
      summary: 'Update a service.'
      operationId: updateAService
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 75
                    type: service
                    name: Consulting
                    description: 'Et et modi ipsum nostrum.'
                    default_rate: 13789
                    unit: day
                    tax_name_1: null
                    tax_rate_1: null
                    tax_name_2: null
                    tax_rate_2: null
                    is_active: true
                    created_at: '2026-04-05T19:38:15.000000Z'
                    updated_at: '2026-04-05T19:38:15.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 75
                      type:
                        type: string
                        example: service
                      name:
                        type: string
                        example: Consulting
                      description:
                        type: string
                        example: 'Et et modi ipsum nostrum.'
                      default_rate:
                        type: integer
                        example: 13789
                      unit:
                        type: string
                        example: day
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      is_active:
                        type: boolean
                        example: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:15.000000Z'
      tags:
        - Services
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                description:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'Et animi quos velit et fugiat.'
                  nullable: true
                default_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 42
                  nullable: true
                type:
                  type: string
                  description: ''
                  example: product
                  enum:
                    - service
                    - product
                  nullable: true
                unit:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: ljnikhwaykcmyuwp
                  nullable: true
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: w
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 89
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: v
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 3
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
              required:
                - name
    delete:
      summary: 'Delete a service.'
      operationId: deleteAService
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Services
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the service.'
        example: 1
        required: true
        schema:
          type: integer
  /api/expenses/bulk-action:
    post:
      summary: 'Bulk action on expenses.'
      operationId: bulkActionOnExpenses
      description: 'Supported actions: `archive`, `unarchive`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Expenses
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: unarchive
                  enum:
                    - archive
                    - unarchive
                    - delete
              required:
                - action
  /api/expenses:
    get:
      summary: 'List expenses.'
      operationId: listExpenses
      description: 'Supports filtering by category, client_id, project_id, is_billable, is_billed, and date range. Meta includes aggregate totals for active expenses.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      user_id: 20
                      client_id: null
                      project_id: null
                      invoice_id: null
                      category: other
                      vendor: null
                      description: null
                      amount: 5000
                      currency: USD
                      tax_amount: 0
                      tax_name: null
                      tax_rate: 0
                      expense_date: '2026-04-05'
                      status: pending
                      is_archived: false
                      is_billable: false
                      is_billed: false
                      receipt_path: null
                      reference: null
                      created_at: '2026-04-05T19:38:20.000000Z'
                      updated_at: '2026-04-05T19:38:20.000000Z'
                    -
                      id: 2
                      user_id: 21
                      client_id: null
                      project_id: null
                      invoice_id: null
                      category: other
                      vendor: null
                      description: null
                      amount: 5000
                      currency: USD
                      tax_amount: 0
                      tax_name: null
                      tax_rate: 0
                      expense_date: '2026-04-05'
                      status: pending
                      is_archived: false
                      is_billable: false
                      is_billed: false
                      receipt_path: null
                      reference: null
                      created_at: '2026-04-05T19:38:21.000000Z'
                      updated_at: '2026-04-05T19:38:21.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        user_id: 20
                        client_id: null
                        project_id: null
                        invoice_id: null
                        category: other
                        vendor: null
                        description: null
                        amount: 5000
                        currency: USD
                        tax_amount: 0
                        tax_name: null
                        tax_rate: 0
                        expense_date: '2026-04-05'
                        status: pending
                        is_archived: false
                        is_billable: false
                        is_billed: false
                        receipt_path: null
                        reference: null
                        created_at: '2026-04-05T19:38:20.000000Z'
                        updated_at: '2026-04-05T19:38:20.000000Z'
                      -
                        id: 2
                        user_id: 21
                        client_id: null
                        project_id: null
                        invoice_id: null
                        category: other
                        vendor: null
                        description: null
                        amount: 5000
                        currency: USD
                        tax_amount: 0
                        tax_name: null
                        tax_rate: 0
                        expense_date: '2026-04-05'
                        status: pending
                        is_archived: false
                        is_billable: false
                        is_billed: false
                        receipt_path: null
                        reference: null
                        created_at: '2026-04-05T19:38:21.000000Z'
                        updated_at: '2026-04-05T19:38:21.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        user_id:
                          type: integer
                          example: 20
                        client_id:
                          type: string
                          example: null
                          nullable: true
                        project_id:
                          type: string
                          example: null
                          nullable: true
                        invoice_id:
                          type: string
                          example: null
                          nullable: true
                        category:
                          type: string
                          example: other
                        vendor:
                          type: string
                          example: null
                          nullable: true
                        description:
                          type: string
                          example: null
                          nullable: true
                        amount:
                          type: integer
                          example: 5000
                        currency:
                          type: string
                          example: USD
                        tax_amount:
                          type: integer
                          example: 0
                        tax_name:
                          type: string
                          example: null
                          nullable: true
                        tax_rate:
                          type: integer
                          example: 0
                        expense_date:
                          type: string
                          example: '2026-04-05'
                        status:
                          type: string
                          example: pending
                        is_archived:
                          type: boolean
                          example: false
                        is_billable:
                          type: boolean
                          example: false
                        is_billed:
                          type: boolean
                          example: false
                        receipt_path:
                          type: string
                          example: null
                          nullable: true
                        reference:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:20.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:20.000000Z'
      tags:
        - Expenses
    post:
      summary: 'Create an expense.'
      operationId: createAnExpense
      description: 'Creates an expense attributed to the authenticated user. Currency defaults to the company currency if not provided.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 3
                    user_id: 22
                    client_id: null
                    project_id: null
                    invoice_id: null
                    category: other
                    vendor: null
                    description: null
                    amount: 5000
                    currency: USD
                    tax_amount: 0
                    tax_name: null
                    tax_rate: 0
                    expense_date: '2026-04-05'
                    status: pending
                    is_archived: false
                    is_billable: false
                    is_billed: false
                    receipt_path: null
                    reference: null
                    created_at: '2026-04-05T19:38:21.000000Z'
                    updated_at: '2026-04-05T19:38:21.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 3
                      user_id:
                        type: integer
                        example: 22
                      client_id:
                        type: string
                        example: null
                        nullable: true
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      category:
                        type: string
                        example: other
                      vendor:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: null
                        nullable: true
                      amount:
                        type: integer
                        example: 5000
                      currency:
                        type: string
                        example: USD
                      tax_amount:
                        type: integer
                        example: 0
                      tax_name:
                        type: string
                        example: null
                        nullable: true
                      tax_rate:
                        type: integer
                        example: 0
                      expense_date:
                        type: string
                        example: '2026-04-05'
                      status:
                        type: string
                        example: pending
                      is_archived:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: false
                      is_billed:
                        type: boolean
                        example: false
                      receipt_path:
                        type: string
                        example: null
                        nullable: true
                      reference:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
      tags:
        - Expenses
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  description: ''
                  example: meals
                  enum:
                    - advertising
                    - bank_fees
                    - contractor_fees
                    - education
                    - equipment
                    - insurance
                    - meals
                    - office_supplies
                    - rent
                    - software
                    - travel_transport
                    - utilities
                    - other
                vendor:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'Et animi quos velit et fugiat.'
                  nullable: true
                amount:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 26
                currency:
                  type: string
                  description: 'Must not be greater than 3 characters.'
                  example: l
                  nullable: true
                tax_amount:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 9
                  nullable: true
                tax_name:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                expense_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:21'
                is_billable:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                  nullable: true
                project_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the projects table.'
                  example: null
                  nullable: true
                reference:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: k
                  nullable: true
              required:
                - category
                - amount
                - expense_date
  '/api/expenses/{id}':
    get:
      summary: 'Get an expense.'
      operationId: getAnExpense
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4
                    user_id: 23
                    client_id: null
                    project_id: null
                    invoice_id: null
                    category: other
                    vendor: null
                    description: null
                    amount: 5000
                    currency: USD
                    tax_amount: 0
                    tax_name: null
                    tax_rate: 0
                    expense_date: '2026-04-05'
                    status: pending
                    is_archived: false
                    is_billable: false
                    is_billed: false
                    receipt_path: null
                    reference: null
                    created_at: '2026-04-05T19:38:21.000000Z'
                    updated_at: '2026-04-05T19:38:21.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4
                      user_id:
                        type: integer
                        example: 23
                      client_id:
                        type: string
                        example: null
                        nullable: true
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      category:
                        type: string
                        example: other
                      vendor:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: null
                        nullable: true
                      amount:
                        type: integer
                        example: 5000
                      currency:
                        type: string
                        example: USD
                      tax_amount:
                        type: integer
                        example: 0
                      tax_name:
                        type: string
                        example: null
                        nullable: true
                      tax_rate:
                        type: integer
                        example: 0
                      expense_date:
                        type: string
                        example: '2026-04-05'
                      status:
                        type: string
                        example: pending
                      is_archived:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: false
                      is_billed:
                        type: boolean
                        example: false
                      receipt_path:
                        type: string
                        example: null
                        nullable: true
                      reference:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
      tags:
        - Expenses
    put:
      summary: 'Update an expense.'
      operationId: updateAnExpense
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 5
                    user_id: 24
                    client_id: null
                    project_id: null
                    invoice_id: null
                    category: other
                    vendor: null
                    description: null
                    amount: 5000
                    currency: USD
                    tax_amount: 0
                    tax_name: null
                    tax_rate: 0
                    expense_date: '2026-04-05'
                    status: pending
                    is_archived: false
                    is_billable: false
                    is_billed: false
                    receipt_path: null
                    reference: null
                    created_at: '2026-04-05T19:38:21.000000Z'
                    updated_at: '2026-04-05T19:38:21.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 5
                      user_id:
                        type: integer
                        example: 24
                      client_id:
                        type: string
                        example: null
                        nullable: true
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      category:
                        type: string
                        example: other
                      vendor:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: null
                        nullable: true
                      amount:
                        type: integer
                        example: 5000
                      currency:
                        type: string
                        example: USD
                      tax_amount:
                        type: integer
                        example: 0
                      tax_name:
                        type: string
                        example: null
                        nullable: true
                      tax_rate:
                        type: integer
                        example: 0
                      expense_date:
                        type: string
                        example: '2026-04-05'
                      status:
                        type: string
                        example: pending
                      is_archived:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: false
                      is_billed:
                        type: boolean
                        example: false
                      receipt_path:
                        type: string
                        example: null
                        nullable: true
                      reference:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:21.000000Z'
      tags:
        - Expenses
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  description: ''
                  example: advertising
                  enum:
                    - advertising
                    - bank_fees
                    - contractor_fees
                    - education
                    - equipment
                    - insurance
                    - meals
                    - office_supplies
                    - rent
                    - software
                    - travel_transport
                    - utilities
                    - other
                vendor:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'Et animi quos velit et fugiat.'
                  nullable: true
                amount:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 26
                currency:
                  type: string
                  description: 'Must not be greater than 3 characters.'
                  example: l
                  nullable: true
                tax_amount:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 9
                  nullable: true
                tax_name:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                expense_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:21'
                is_billable:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                  nullable: true
                project_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the projects table.'
                  example: null
                  nullable: true
                reference:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: k
                  nullable: true
              required:
                - amount
                - expense_date
    delete:
      summary: 'Delete an expense.'
      operationId: deleteAnExpense
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Expenses
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the expense.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/expenses/{expense_id}/archive':
    post:
      summary: 'Archive an expense.'
      operationId: archiveAnExpense
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Expenses
    parameters:
      -
        in: path
        name: expense_id
        description: 'The ID of the expense.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/expenses/{expense_id}/unarchive':
    post:
      summary: 'Unarchive an expense.'
      operationId: unarchiveAnExpense
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Expenses
    parameters:
      -
        in: path
        name: expense_id
        description: 'The ID of the expense.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/expenses/{expense_id}/receipt':
    post:
      summary: 'Upload a receipt for an expense.'
      operationId: uploadAReceiptForAnExpense
      description: 'Accepts JPEG, PNG, GIF, WebP, or PDF files up to 5 MB.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 6
                    user_id: 25
                    client_id: null
                    project_id: null
                    invoice_id: null
                    category: other
                    vendor: null
                    description: null
                    amount: 5000
                    currency: USD
                    tax_amount: 0
                    tax_name: null
                    tax_rate: 0
                    expense_date: '2026-04-05'
                    status: pending
                    is_archived: false
                    is_billable: false
                    is_billed: false
                    receipt_path: null
                    reference: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 6
                      user_id:
                        type: integer
                        example: 25
                      client_id:
                        type: string
                        example: null
                        nullable: true
                      project_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      category:
                        type: string
                        example: other
                      vendor:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: null
                        nullable: true
                      amount:
                        type: integer
                        example: 5000
                      currency:
                        type: string
                        example: USD
                      tax_amount:
                        type: integer
                        example: 0
                      tax_name:
                        type: string
                        example: null
                        nullable: true
                      tax_rate:
                        type: integer
                        example: 0
                      expense_date:
                        type: string
                        example: '2026-04-05'
                      status:
                        type: string
                        example: pending
                      is_archived:
                        type: boolean
                        example: false
                      is_billable:
                        type: boolean
                        example: false
                      is_billed:
                        type: boolean
                        example: false
                      receipt_path:
                        type: string
                        example: null
                        nullable: true
                      reference:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - Expenses
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                receipt:
                  type: string
                  description: 'Must not be greater than 5120 characters.'
                  example: b
              required:
                - receipt
    get:
      summary: 'Download an expense receipt.'
      operationId: downloadAnExpenseReceipt
      description: 'Streams the uploaded receipt file as a download. Returns 404 if no receipt is attached.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            text/plain:
              schema:
                type: string
                example: file
      tags:
        - Expenses
    parameters:
      -
        in: path
        name: expense_id
        description: 'The ID of the expense.'
        example: 16
        required: true
        schema:
          type: integer
  /api/credits/bulk-action:
    post:
      summary: 'Bulk action on credits.'
      operationId: bulkActionOnCredits
      description: 'Supported actions: `archive`, `unarchive`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - Credits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: unarchive
                  enum:
                    - archive
                    - unarchive
                    - delete
              required:
                - action
  /api/credits:
    get:
      summary: 'List credits.'
      operationId: listCredits
      description: 'Supports filtering by client_id, type, and has_balance. Results are paginated with active/archived counts in the meta.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      client_id: 186
                      invoice_id: null
                      type: credit_note
                      is_archived: false
                      amount: 26768
                      balance: 26768
                      currency: USD
                      description: 'Quidem nostrum qui commodi incidunt iure odit.'
                      date: '2026-04-05T00:00:00.000000Z'
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                    -
                      id: 2
                      client_id: 187
                      invoice_id: null
                      type: credit_note
                      is_archived: false
                      amount: 13913
                      balance: 13913
                      currency: USD
                      description: 'Ratione nemo voluptate accusamus ut et recusandae modi rerum.'
                      date: '2026-04-05T00:00:00.000000Z'
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        client_id: 186
                        invoice_id: null
                        type: credit_note
                        is_archived: false
                        amount: 26768
                        balance: 26768
                        currency: USD
                        description: 'Quidem nostrum qui commodi incidunt iure odit.'
                        date: '2026-04-05T00:00:00.000000Z'
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                      -
                        id: 2
                        client_id: 187
                        invoice_id: null
                        type: credit_note
                        is_archived: false
                        amount: 13913
                        balance: 13913
                        currency: USD
                        description: 'Ratione nemo voluptate accusamus ut et recusandae modi rerum.'
                        date: '2026-04-05T00:00:00.000000Z'
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        client_id:
                          type: integer
                          example: 186
                        invoice_id:
                          type: string
                          example: null
                          nullable: true
                        type:
                          type: string
                          example: credit_note
                        is_archived:
                          type: boolean
                          example: false
                        amount:
                          type: integer
                          example: 26768
                        balance:
                          type: integer
                          example: 26768
                        currency:
                          type: string
                          example: USD
                        description:
                          type: string
                          example: 'Quidem nostrum qui commodi incidunt iure odit.'
                        date:
                          type: string
                          example: '2026-04-05T00:00:00.000000Z'
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
      tags:
        - Credits
    post:
      summary: 'Create a credit.'
      operationId: createACredit
      description: 'Creates a credit note for a client. The initial `balance` is automatically set equal to `amount`. Currency defaults to the company currency if not provided.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 3
                    client_id: 188
                    invoice_id: null
                    type: credit_note
                    is_archived: false
                    amount: 21638
                    balance: 21638
                    currency: USD
                    description: 'Modi deserunt aut ab provident perspiciatis.'
                    date: '2026-04-05T00:00:00.000000Z'
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 3
                      client_id:
                        type: integer
                        example: 188
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      type:
                        type: string
                        example: credit_note
                      is_archived:
                        type: boolean
                        example: false
                      amount:
                        type: integer
                        example: 21638
                      balance:
                        type: integer
                        example: 21638
                      currency:
                        type: string
                        example: USD
                      description:
                        type: string
                        example: 'Modi deserunt aut ab provident perspiciatis.'
                      date:
                        type: string
                        example: '2026-04-05T00:00:00.000000Z'
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - Credits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: architecto
                invoice_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the invoices table.'
                  example: null
                  nullable: true
                type:
                  type: string
                  description: ''
                  example: overpayment
                  enum:
                    - credit_note
                    - overpayment
                    - prepayment
                amount:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 22
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: gzm
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'Et fugiat sunt nihil accusantium.'
                  nullable: true
                date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:22'
              required:
                - client_id
                - type
                - amount
                - date
  '/api/credits/{id}':
    get:
      summary: 'Get a credit.'
      operationId: getACredit
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 4
                    client_id: 189
                    invoice_id: null
                    type: credit_note
                    is_archived: false
                    amount: 26768
                    balance: 26768
                    currency: USD
                    description: 'Quidem nostrum qui commodi incidunt iure odit.'
                    date: '2026-04-05T00:00:00.000000Z'
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 4
                      client_id:
                        type: integer
                        example: 189
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      type:
                        type: string
                        example: credit_note
                      is_archived:
                        type: boolean
                        example: false
                      amount:
                        type: integer
                        example: 26768
                      balance:
                        type: integer
                        example: 26768
                      currency:
                        type: string
                        example: USD
                      description:
                        type: string
                        example: 'Quidem nostrum qui commodi incidunt iure odit.'
                      date:
                        type: string
                        example: '2026-04-05T00:00:00.000000Z'
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - Credits
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the credit.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/credits/{credit_id}/archive':
    post:
      summary: 'Archive a credit.'
      operationId: archiveACredit
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Credits
    parameters:
      -
        in: path
        name: credit_id
        description: 'The ID of the credit.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/credits/{credit_id}/unarchive':
    post:
      summary: 'Unarchive a credit.'
      operationId: unarchiveACredit
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Credits
    parameters:
      -
        in: path
        name: credit_id
        description: 'The ID of the credit.'
        example: 16
        required: true
        schema:
          type: integer
  '/api/clients/{client_id}/credits':
    get:
      summary: 'Get client credit balance.'
      operationId: getClientCreditBalance
      description: 'Returns the total available credit balance and list of credits with a remaining balance for the given client.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    client_id: 1
                    available_balance: 5000
                    credits: []
                properties:
                  data:
                    type: object
                    properties:
                      client_id:
                        type: integer
                        example: 1
                      available_balance:
                        type: integer
                        example: 5000
                      credits:
                        type: array
                        example: []
      tags:
        - Credits
    parameters:
      -
        in: path
        name: client_id
        description: 'The ID of the client.'
        example: 4
        required: true
        schema:
          type: integer
  '/api/credits/{credit_id}/apply':
    post:
      summary: 'Apply credit to an invoice.'
      operationId: applyCreditToAnInvoice
      description: "Applies part or all of a credit's balance to an outstanding invoice. Both must belong to the same client.\nThe invoice must be in a payable state (sent, viewed, partial, or overdue). Automatically transitions the\ninvoice to paid or partial based on the resulting amount_due."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 5
                    client_id: 190
                    invoice_id: null
                    type: credit_note
                    is_archived: false
                    amount: 11278
                    balance: 11278
                    currency: USD
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    date: '2026-04-05T00:00:00.000000Z'
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 5
                      client_id:
                        type: integer
                        example: 190
                      invoice_id:
                        type: string
                        example: null
                        nullable: true
                      type:
                        type: string
                        example: credit_note
                      is_archived:
                        type: boolean
                        example: false
                      amount:
                        type: integer
                        example: 11278
                      balance:
                        type: integer
                        example: 11278
                      currency:
                        type: string
                        example: USD
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      date:
                        type: string
                        example: '2026-04-05T00:00:00.000000Z'
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - Credits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                invoice_id:
                  type: string
                  description: ''
                  example: architecto
                amount:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 22
              required:
                - invoice_id
                - amount
    parameters:
      -
        in: path
        name: credit_id
        description: 'The ID of the credit.'
        example: 16
        required: true
        schema:
          type: integer
  /api/recurring-invoices/bulk-action:
    post:
      summary: 'Bulk action on recurring invoices.'
      operationId: bulkActionOnRecurringInvoices
      description: 'Supported actions: `activate`, `pause`, `archive`, `delete`. Returns the count of affected records.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    affected: 3
                properties:
                  data:
                    type: object
                    properties:
                      affected:
                        type: integer
                        example: 3
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ''
                  example:
                    - 16
                  items:
                    type: integer
                action:
                  type: string
                  description: ''
                  example: architecto
              required:
                - action
  /api/recurring-invoices:
    get:
      summary: 'List recurring invoices.'
      operationId: listRecurringInvoices
      description: 'Supports filtering by status, client_id, and frequency. Results are paginated and include per-status counts in the meta.'
      parameters:
        -
          in: query
          name: 'filter[status]'
          description: 'Filter by status.'
          example: active
          required: false
          schema:
            type: string
            description: 'Filter by status.'
            example: active
        -
          in: query
          name: 'filter[client_id]'
          description: 'Filter by client ID.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by client ID.'
            example: 1
        -
          in: query
          name: 'filter[frequency]'
          description: 'Filter by frequency.'
          example: monthly
          required: false
          schema:
            type: string
            description: 'Filter by frequency.'
            example: monthly
        -
          in: query
          name: sort
          description: 'Sort field (prefix with - for descending).'
          example: next_generate_date
          required: false
          schema:
            type: string
            description: 'Sort field (prefix with - for descending).'
            example: next_generate_date
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 38
                      client_id: 191
                      title: 'Adipisci quidem nostrum qui.'
                      status: active
                      is_archived: false
                      frequency: monthly
                      frequency_label: Monthly
                      interval: 1
                      start_date: '2026-04-05'
                      end_date: null
                      next_generate_date: '2026-04-05'
                      last_generated_at: null
                      auto_send: false
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      notes: null
                      payment_terms: 30
                      occurrences_generated: 0
                      max_occurrences: null
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                    -
                      id: 39
                      client_id: 192
                      title: 'Qui repudiandae laboriosam.'
                      status: active
                      is_archived: false
                      frequency: monthly
                      frequency_label: Monthly
                      interval: 1
                      start_date: '2026-04-05'
                      end_date: null
                      next_generate_date: '2026-04-05'
                      last_generated_at: null
                      auto_send: false
                      currency: USD
                      subtotal: 0
                      tax_total: 0
                      discount_type: null
                      discount_value: null
                      discount_total: 0
                      total: 0
                      notes: null
                      payment_terms: 30
                      occurrences_generated: 0
                      max_occurrences: null
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 38
                        client_id: 191
                        title: 'Adipisci quidem nostrum qui.'
                        status: active
                        is_archived: false
                        frequency: monthly
                        frequency_label: Monthly
                        interval: 1
                        start_date: '2026-04-05'
                        end_date: null
                        next_generate_date: '2026-04-05'
                        last_generated_at: null
                        auto_send: false
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        notes: null
                        payment_terms: 30
                        occurrences_generated: 0
                        max_occurrences: null
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                      -
                        id: 39
                        client_id: 192
                        title: 'Qui repudiandae laboriosam.'
                        status: active
                        is_archived: false
                        frequency: monthly
                        frequency_label: Monthly
                        interval: 1
                        start_date: '2026-04-05'
                        end_date: null
                        next_generate_date: '2026-04-05'
                        last_generated_at: null
                        auto_send: false
                        currency: USD
                        subtotal: 0
                        tax_total: 0
                        discount_type: null
                        discount_value: null
                        discount_total: 0
                        total: 0
                        notes: null
                        payment_terms: 30
                        occurrences_generated: 0
                        max_occurrences: null
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 38
                        client_id:
                          type: integer
                          example: 191
                        title:
                          type: string
                          example: 'Adipisci quidem nostrum qui.'
                        status:
                          type: string
                          example: active
                        is_archived:
                          type: boolean
                          example: false
                        frequency:
                          type: string
                          example: monthly
                        frequency_label:
                          type: string
                          example: Monthly
                        interval:
                          type: integer
                          example: 1
                        start_date:
                          type: string
                          example: '2026-04-05'
                        end_date:
                          type: string
                          example: null
                          nullable: true
                        next_generate_date:
                          type: string
                          example: '2026-04-05'
                        last_generated_at:
                          type: string
                          example: null
                          nullable: true
                        auto_send:
                          type: boolean
                          example: false
                        currency:
                          type: string
                          example: USD
                        subtotal:
                          type: integer
                          example: 0
                        tax_total:
                          type: integer
                          example: 0
                        discount_type:
                          type: string
                          example: null
                          nullable: true
                        discount_value:
                          type: string
                          example: null
                          nullable: true
                        discount_total:
                          type: integer
                          example: 0
                        total:
                          type: integer
                          example: 0
                        notes:
                          type: string
                          example: null
                          nullable: true
                        payment_terms:
                          type: integer
                          example: 30
                        occurrences_generated:
                          type: integer
                          example: 0
                        max_occurrences:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
    post:
      summary: 'Create a recurring invoice.'
      operationId: createARecurringInvoice
      description: 'Creates an active recurring invoice template. The `next_generate_date` is set to `start_date` and invoices are generated automatically on schedule. Pass `line_items` to attach them in the same request.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 40
                    client_id: 193
                    title: 'Et animi quos.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 40
                      client_id:
                        type: integer
                        example: 193
                      title:
                        type: string
                        example: 'Et animi quos.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: architecto
                title:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                frequency:
                  type: string
                  description: ''
                  example: quarterly
                  enum:
                    - weekly
                    - monthly
                    - quarterly
                    - yearly
                    - custom
                interval:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 67
                  nullable: true
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:22'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after <code>start_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                auto_send:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                payment_terms:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
                next_generate_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:22'
                  nullable: true
                max_occurrences:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 66
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
              required:
                - client_id
                - title
                - frequency
                - start_date
  '/api/recurring-invoices/{id}':
    get:
      summary: 'Get a recurring invoice.'
      operationId: getARecurringInvoice
      description: 'Includes line items, client, and the list of invoices generated from this template.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 41
                    client_id: 194
                    title: 'Adipisci quidem nostrum qui.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 41
                      client_id:
                        type: integer
                        example: 194
                      title:
                        type: string
                        example: 'Adipisci quidem nostrum qui.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
    put:
      summary: 'Update a recurring invoice.'
      operationId: updateARecurringInvoice
      description: 'If `line_items` is provided, the full set of line items is synced. Omit `line_items` to update template fields only without touching line items.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 42
                    client_id: 195
                    title: 'Et animi quos.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 42
                      client_id:
                        type: integer
                        example: 195
                      title:
                        type: string
                        example: 'Et animi quos.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the clients table.'
                  example: null
                title:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                frequency:
                  type: string
                  description: ''
                  example: quarterly
                  enum:
                    - weekly
                    - monthly
                    - quarterly
                    - yearly
                    - custom
                interval:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 22
                  nullable: true
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:22'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after <code>start_date</code>.'
                  example: '2052-04-28'
                  nullable: true
                auto_send:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: ngz
                  nullable: true
                discount_type:
                  type: string
                  description: ''
                  example: percentage
                  enum:
                    - percentage
                    - fixed
                  nullable: true
                discount_value:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                notes:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                payment_terms:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
                next_generate_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:22'
                  nullable: true
                max_occurrences:
                  type: integer
                  description: 'Must be at least 1.'
                  example: 66
                  nullable: true
                line_items:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      description:
                        type: string
                        description: 'Must not be greater than 1000 characters.'
                        example: 'Velit et fugiat sunt nihil accusantium.'
                      quantity:
                        type: number
                        description: 'Must be at least 0.0001.'
                        example: 52
                      unit_price:
                        type: number
                        description: 'Must be at least 0.'
                        example: 8
                      service_id:
                        type: string
                        description: 'The <code>id</code> of an existing record in the services table.'
                        example: null
                        nullable: true
                      tax_name:
                        type: string
                        description: 'Must not be greater than 50 characters.'
                        example: k
                        nullable: true
                      tax_rate:
                        type: number
                        description: 'Must be at least 0. Must not be greater than 100.'
                        example: 14
                        nullable: true
                      sort_order:
                        type: integer
                        description: ''
                        example: 16
                        nullable: true
                    required:
                      - description
                      - quantity
                      - unit_price
    delete:
      summary: 'Delete a recurring invoice.'
      operationId: deleteARecurringInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the recurring invoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurring_invoice_id}/line-items':
    get:
      summary: 'List line items for a recurring invoice.'
      operationId: listLineItemsForARecurringInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 87
                      service_id: null
                      time_entry_id: null
                      description: 'Nostrum qui commodi incidunt iure.'
                      quantity: 1.02
                      unit_price: '13053.000000'
                      amount: 13314
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                    -
                      id: 88
                      service_id: null
                      time_entry_id: null
                      description: 'Nemo voluptate accusamus ut et.'
                      quantity: 8.73
                      unit_price: '36405.000000'
                      amount: 317816
                      tax_name_1: null
                      tax_rate_1: null
                      tax_amount_1: 0
                      tax_name_2: null
                      tax_rate_2: null
                      tax_amount_2: 0
                      sort_order: 0
                      is_late_fee: false
                      created_at: '2026-04-05T19:38:22.000000Z'
                      updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 87
                        service_id: null
                        time_entry_id: null
                        description: 'Nostrum qui commodi incidunt iure.'
                        quantity: 1.02
                        unit_price: '13053.000000'
                        amount: 13314
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                      -
                        id: 88
                        service_id: null
                        time_entry_id: null
                        description: 'Nemo voluptate accusamus ut et.'
                        quantity: 8.73
                        unit_price: '36405.000000'
                        amount: 317816
                        tax_name_1: null
                        tax_rate_1: null
                        tax_amount_1: 0
                        tax_name_2: null
                        tax_rate_2: null
                        tax_amount_2: 0
                        sort_order: 0
                        is_late_fee: false
                        created_at: '2026-04-05T19:38:22.000000Z'
                        updated_at: '2026-04-05T19:38:22.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 87
                        service_id:
                          type: string
                          example: null
                          nullable: true
                        time_entry_id:
                          type: string
                          example: null
                          nullable: true
                        description:
                          type: string
                          example: 'Nostrum qui commodi incidunt iure.'
                        quantity:
                          type: number
                          example: 1.02
                        unit_price:
                          type: string
                          example: '13053.000000'
                        amount:
                          type: integer
                          example: 13314
                        tax_name_1:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_1:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_1:
                          type: integer
                          example: 0
                        tax_name_2:
                          type: string
                          example: null
                          nullable: true
                        tax_rate_2:
                          type: string
                          example: null
                          nullable: true
                        tax_amount_2:
                          type: integer
                          example: 0
                        sort_order:
                          type: integer
                          example: 0
                        is_late_fee:
                          type: boolean
                          example: false
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
    post:
      summary: 'Add a line item to a recurring invoice.'
      operationId: addALineItemToARecurringInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 89
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 89
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    parameters:
      -
        in: path
        name: recurring_invoice_id
        description: 'The ID of the recurring invoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurring_invoice_id}/line-items/{lineItem_id}':
    put:
      summary: 'Update a line item on a recurring invoice.'
      operationId: updateALineItemOnARecurringInvoice
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 90
                    service_id: null
                    time_entry_id: null
                    description: 'Quos velit et fugiat sunt nihil accusantium harum.'
                    quantity: 9.96
                    unit_price: '11278.000000'
                    amount: 112329
                    tax_name_1: null
                    tax_rate_1: null
                    tax_amount_1: 0
                    tax_name_2: null
                    tax_rate_2: null
                    tax_amount_2: 0
                    sort_order: 0
                    is_late_fee: false
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 90
                      service_id:
                        type: string
                        example: null
                        nullable: true
                      time_entry_id:
                        type: string
                        example: null
                        nullable: true
                      description:
                        type: string
                        example: 'Quos velit et fugiat sunt nihil accusantium harum.'
                      quantity:
                        type: number
                        example: 9.96
                      unit_price:
                        type: string
                        example: '11278.000000'
                      amount:
                        type: integer
                        example: 112329
                      tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_1:
                        type: integer
                        example: 0
                      tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      tax_amount_2:
                        type: integer
                        example: 0
                      sort_order:
                        type: integer
                        example: 0
                      is_late_fee:
                        type: boolean
                        example: false
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                service_id:
                  type: string
                  description: 'The <code>id</code> of an existing record in the services table.'
                  example: null
                  nullable: true
                description:
                  type: string
                  description: 'Must not be greater than 1000 characters.'
                  example: 'Eius et animi quos velit et.'
                quantity:
                  type: number
                  description: 'Must be at least 0.0001.'
                  example: 60
                unit_price:
                  type: number
                  description: 'Must be at least 0.'
                  example: 42
                tax_name_1:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: l
                  nullable: true
                tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 19
                  nullable: true
                tax_name_2:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 5
                  nullable: true
                sort_order:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
              required:
                - description
                - quantity
                - unit_price
    delete:
      summary: 'Delete a line item from a recurring invoice.'
      operationId: deleteALineItemFromARecurringInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurring_invoice_id
        description: 'The ID of the recurring invoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem_id
        description: 'The ID of the lineItem.'
        example: 4
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
      -
        in: path
        name: lineItem
        description: 'The line item ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/move':
    post:
      summary: 'Move a recurring invoice to another company.'
      operationId: moveARecurringInvoiceToAnotherCompany
      description: 'Reassigns the template to the target company. Clears the client association, nullifies service references on line items, and unlinks previously generated invoices in the source company.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 47
                    client_id: 200
                    title: 'Et animi quos.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 47
                      client_id:
                        type: integer
                        example: 200
                      title:
                        type: string
                        example: 'Et animi quos.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                target_company_id:
                  type: integer
                  description: ''
                  example: 16
              required:
                - target_company_id
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/archive':
    post:
      summary: 'Archive a recurring invoice.'
      operationId: archiveARecurringInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/unarchive':
    post:
      summary: 'Unarchive a recurring invoice.'
      operationId: unarchiveARecurringInvoice
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/pause':
    post:
      summary: 'Pause a recurring invoice.'
      operationId: pauseARecurringInvoice
      description: 'Stops automatic invoice generation. Only active recurring invoices can be paused.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 48
                    client_id: 201
                    title: 'Adipisci quidem nostrum qui.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 48
                      client_id:
                        type: integer
                        example: 201
                      title:
                        type: string
                        example: 'Adipisci quidem nostrum qui.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/resume':
    post:
      summary: 'Resume a paused recurring invoice.'
      operationId: resumeAPausedRecurringInvoice
      description: 'Resumes automatic invoice generation by setting the status back to active. Only paused recurring invoices can be resumed.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 49
                    client_id: 202
                    title: 'Adipisci quidem nostrum qui.'
                    status: active
                    is_archived: false
                    frequency: monthly
                    frequency_label: Monthly
                    interval: 1
                    start_date: '2026-04-05'
                    end_date: null
                    next_generate_date: '2026-04-05'
                    last_generated_at: null
                    auto_send: false
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    payment_terms: 30
                    occurrences_generated: 0
                    max_occurrences: null
                    created_at: '2026-04-05T19:38:22.000000Z'
                    updated_at: '2026-04-05T19:38:22.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 49
                      client_id:
                        type: integer
                        example: 202
                      title:
                        type: string
                        example: 'Adipisci quidem nostrum qui.'
                      status:
                        type: string
                        example: active
                      is_archived:
                        type: boolean
                        example: false
                      frequency:
                        type: string
                        example: monthly
                      frequency_label:
                        type: string
                        example: Monthly
                      interval:
                        type: integer
                        example: 1
                      start_date:
                        type: string
                        example: '2026-04-05'
                      end_date:
                        type: string
                        example: null
                        nullable: true
                      next_generate_date:
                        type: string
                        example: '2026-04-05'
                      last_generated_at:
                        type: string
                        example: null
                        nullable: true
                      auto_send:
                        type: boolean
                        example: false
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: integer
                        example: 30
                      occurrences_generated:
                        type: integer
                        example: 0
                      max_occurrences:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:22.000000Z'
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  '/api/recurring-invoices/{recurringInvoice_id}/generate':
    post:
      summary: 'Manually generate an invoice from a recurring invoice.'
      operationId: manuallyGenerateAnInvoiceFromARecurringInvoice
      description: 'Immediately generates the next invoice regardless of the scheduled date. Returns 422 if the maximum occurrence limit has been reached.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1617
                    uuid: 5134a4d7-1b9b-43c7-bc68-9dbc2f15bb1f
                    client_id: 203
                    recurring_invoice_id: null
                    invoice_number: INV-52976
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    due_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    amount_paid: 0
                    amount_due: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    paid_at: null
                    late_fee_amount: 0
                    late_fee_applied_at: null
                    reminders_sent: 0
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                  status: '201'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1617
                      uuid:
                        type: string
                        example: 5134a4d7-1b9b-43c7-bc68-9dbc2f15bb1f
                      client_id:
                        type: integer
                        example: 203
                      recurring_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      invoice_number:
                        type: string
                        example: INV-52976
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      due_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      amount_paid:
                        type: integer
                        example: 0
                      amount_due:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      paid_at:
                        type: string
                        example: null
                        nullable: true
                      late_fee_amount:
                        type: integer
                        example: 0
                      late_fee_applied_at:
                        type: string
                        example: null
                        nullable: true
                      reminders_sent:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                  status:
                    type: string
                    example: '201'
      tags:
        - 'Recurring Invoices'
    parameters:
      -
        in: path
        name: recurringInvoice_id
        description: 'The ID of the recurringInvoice.'
        example: 6
        required: true
        schema:
          type: integer
      -
        in: path
        name: recurringInvoice
        description: 'The recurring invoice ID.'
        example: 1
        required: true
        schema:
          type: integer
  /api/billing/prices:
    get:
      summary: 'List Stripe prices for all plans.'
      operationId: listStripePricesForAllPlans
      description: 'Returns active recurring prices per plan keyed by plan name. Cached for one hour.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    starter:
                      -
                        price_id: price_starter_monthly
                        amount: 900
                        currency: usd
                        interval: month
                        interval_count: 1
                      -
                        price_id: price_starter_annual
                        amount: 700
                        currency: usd
                        interval: month
                        interval_count: 1
                    pro:
                      -
                        price_id: price_pro_monthly
                        amount: 1800
                        currency: usd
                        interval: month
                        interval_count: 1
                properties:
                  data:
                    type: object
                    properties:
                      starter:
                        type: array
                        example:
                          -
                            price_id: price_starter_monthly
                            amount: 900
                            currency: usd
                            interval: month
                            interval_count: 1
                          -
                            price_id: price_starter_annual
                            amount: 700
                            currency: usd
                            interval: month
                            interval_count: 1
                        items:
                          type: object
                          properties:
                            price_id:
                              type: string
                              example: price_starter_monthly
                            amount:
                              type: integer
                              example: 900
                            currency:
                              type: string
                              example: usd
                            interval:
                              type: string
                              example: month
                            interval_count:
                              type: integer
                              example: 1
                      pro:
                        type: array
                        example:
                          -
                            price_id: price_pro_monthly
                            amount: 1800
                            currency: usd
                            interval: month
                            interval_count: 1
                        items:
                          type: object
                          properties:
                            price_id:
                              type: string
                              example: price_pro_monthly
                            amount:
                              type: integer
                              example: 1800
                            currency:
                              type: string
                              example: usd
                            interval:
                              type: string
                              example: month
                            interval_count:
                              type: integer
                              example: 1
      tags:
        - Billing
  /api/billing/subscription:
    get:
      summary: 'Get current subscription.'
      operationId: getCurrentSubscription
      description: "Returns the authenticated user's active subscription or a default free plan object."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    plan: starter
                    status: active
                    trial_ends_at: null
                    current_period_end: '2026-05-01T00:00:00Z'
                properties:
                  data:
                    type: object
                    properties:
                      plan:
                        type: string
                        example: starter
                      status:
                        type: string
                        example: active
                      trial_ends_at:
                        type: string
                        example: null
                        nullable: true
                      current_period_end:
                        type: string
                        example: '2026-05-01T00:00:00Z'
      tags:
        - Billing
  /api/billing/plans:
    get:
      summary: 'List available plans.'
      operationId: listAvailablePlans
      description: 'Returns all plan tiers and their feature limits.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      plan: free
                      max_clients: 5
                      max_invoices_per_month: 5
                      max_projects: 3
                      max_members: 1
                      max_companies: 1
                      feature_api_access: false
                      feature_recurring_invoices: false
                      feature_time_tracking: false
                      feature_quotes: false
                      feature_client_portal: false
                    -
                      id: 2
                      plan: starter
                      max_clients: 25
                      max_invoices_per_month: 50
                      max_projects: 10
                      max_members: 3
                      max_companies: 2
                      feature_api_access: false
                      feature_recurring_invoices: true
                      feature_time_tracking: true
                      feature_quotes: true
                      feature_client_portal: true
                    -
                      id: 3
                      plan: pro
                      max_clients: null
                      max_invoices_per_month: null
                      max_projects: null
                      max_members: 25
                      max_companies: 5
                      feature_api_access: true
                      feature_recurring_invoices: true
                      feature_time_tracking: true
                      feature_quotes: true
                      feature_client_portal: true
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        plan: free
                        max_clients: 5
                        max_invoices_per_month: 5
                        max_projects: 3
                        max_members: 1
                        max_companies: 1
                        feature_api_access: false
                        feature_recurring_invoices: false
                        feature_time_tracking: false
                        feature_quotes: false
                        feature_client_portal: false
                      -
                        id: 2
                        plan: starter
                        max_clients: 25
                        max_invoices_per_month: 50
                        max_projects: 10
                        max_members: 3
                        max_companies: 2
                        feature_api_access: false
                        feature_recurring_invoices: true
                        feature_time_tracking: true
                        feature_quotes: true
                        feature_client_portal: true
                      -
                        id: 3
                        plan: pro
                        max_clients: null
                        max_invoices_per_month: null
                        max_projects: null
                        max_members: 25
                        max_companies: 5
                        feature_api_access: true
                        feature_recurring_invoices: true
                        feature_time_tracking: true
                        feature_quotes: true
                        feature_client_portal: true
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        plan:
                          type: string
                          example: free
                        max_clients:
                          type: integer
                          example: 5
                        max_invoices_per_month:
                          type: integer
                          example: 5
                        max_projects:
                          type: integer
                          example: 3
                        max_members:
                          type: integer
                          example: 1
                        max_companies:
                          type: integer
                          example: 1
                        feature_api_access:
                          type: boolean
                          example: false
                        feature_recurring_invoices:
                          type: boolean
                          example: false
                        feature_time_tracking:
                          type: boolean
                          example: false
                        feature_quotes:
                          type: boolean
                          example: false
                        feature_client_portal:
                          type: boolean
                          example: false
      tags:
        - Billing
  /api/billing/usage:
    get:
      summary: 'Get current plan usage.'
      operationId: getCurrentPlanUsage
      description: "Returns usage counts for the authenticated user's companies against their plan limits."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    clients: 12
                    invoices_this_month: 8
                    projects: 4
                    team_members: 2
                    companies: 1
                    max_companies: 2
                properties:
                  data:
                    type: object
                    properties:
                      clients:
                        type: integer
                        example: 12
                      invoices_this_month:
                        type: integer
                        example: 8
                      projects:
                        type: integer
                        example: 4
                      team_members:
                        type: integer
                        example: 2
                      companies:
                        type: integer
                        example: 1
                      max_companies:
                        type: integer
                        example: 2
      tags:
        - Billing
  /api/billing/invoices:
    get:
      summary: 'List Stripe billing invoices.'
      operationId: listStripeBillingInvoices
      description: "Returns the last 12 Stripe invoices for the authenticated user's subscription.\nReturns an empty array if the user has no Stripe customer ID."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      data:
                        -
                          id: in_xxx
                          number: INV-0001
                          amount: 900
                          currency: USD
                          status: paid
                          date: '2026-03-01'
                          pdf_url: 'https://pay.stripe.com/invoice/xxx/pdf'
                    properties:
                      data:
                        type: array
                        example:
                          -
                            id: in_xxx
                            number: INV-0001
                            amount: 900
                            currency: USD
                            status: paid
                            date: '2026-03-01'
                            pdf_url: 'https://pay.stripe.com/invoice/xxx/pdf'
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              example: in_xxx
                            number:
                              type: string
                              example: INV-0001
                            amount:
                              type: integer
                              example: 900
                            currency:
                              type: string
                              example: USD
                            status:
                              type: string
                              example: paid
                            date:
                              type: string
                              example: '2026-03-01'
                            pdf_url:
                              type: string
                              example: 'https://pay.stripe.com/invoice/xxx/pdf'
                  -
                    description: 'No Stripe customer'
                    type: object
                    example:
                      data: []
                    properties:
                      data:
                        type: array
                        example: []
      tags:
        - Billing
  /api/billing/checkout:
    post:
      summary: 'Create a Stripe Checkout session.'
      operationId: createAStripeCheckoutSession
      description: 'Creates a Stripe Checkout session for the given plan and price. Returns the hosted checkout URL.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    checkout_url: 'https://checkout.stripe.com/pay/cs_live_xxx'
                    plan: starter
                properties:
                  data:
                    type: object
                    properties:
                      checkout_url:
                        type: string
                        example: 'https://checkout.stripe.com/pay/cs_live_xxx'
                      plan:
                        type: string
                        example: starter
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Plan not configured.'
                properties:
                  message:
                    type: string
                    example: 'Plan not configured.'
      tags:
        - Billing
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                plan:
                  type: string
                  description: 'The plan to subscribe to.'
                  example: starter
                price_id:
                  type: string
                  description: 'The Stripe price ID. Must start with `price_`.'
                  example: price_abc123
              required:
                - plan
                - price_id
  /api/billing/portal:
    post:
      summary: 'Get Stripe Billing Portal URL.'
      operationId: getStripeBillingPortalURL
      description: "Returns a URL to the Stripe Customer Portal where the user can manage their subscription.\nReturns `null` if the user has no Stripe customer ID."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      data:
                        portal_url: 'https://billing.stripe.com/session/xxx'
                    properties:
                      data:
                        type: object
                        properties:
                          portal_url:
                            type: string
                            example: 'https://billing.stripe.com/session/xxx'
                  -
                    description: 'No Stripe customer'
                    type: object
                    example:
                      data:
                        portal_url: null
                    properties:
                      data:
                        type: object
                        properties:
                          portal_url:
                            type: string
                            example: null
                            nullable: true
      tags:
        - Billing
  /api/settings:
    get:
      summary: 'Get company settings.'
      operationId: getCompanySettings
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 178
                    uuid: 53a3ef0f-7120-4769-9543-8498f8da2a40
                    name: 'Price Ltd'
                    legal_name: null
                    email: dare.emelie@baumbach.org
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 178
                      uuid:
                        type: string
                        example: 53a3ef0f-7120-4769-9543-8498f8da2a40
                      name:
                        type: string
                        example: 'Price Ltd'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: dare.emelie@baumbach.org
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
      tags:
        - Settings
    put:
      summary: 'Update company settings.'
      operationId: updateCompanySettings
      description: 'Updates general company settings including address, currency, invoice/quote prefix, default tax rates, default payment terms, and hourly rate. All fields are optional (PATCH semantics).'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 179
                    uuid: 303015f8-8550-415a-a3b8-eee3d4976f0e
                    name: 'Considine LLC'
                    legal_name: null
                    email: ernie.nitzsche@ankunding.biz
                    phone: null
                    address_line_1: null
                    address_line_2: null
                    city: null
                    state: null
                    postal_code: null
                    country: null
                    currency: USD
                    tax_number: null
                    logo_path: null
                    invoice_prefix: INV-
                    quote_prefix: QUO-
                    invoice_layout: classic
                    default_payment_terms: 30
                    default_hourly_rate: null
                    default_tax_name_1: null
                    default_tax_rate_1: null
                    default_tax_name_2: null
                    default_tax_rate_2: null
                    late_fee_type: null
                    late_fee_value: null
                    late_fee_days: null
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 179
                      uuid:
                        type: string
                        example: 303015f8-8550-415a-a3b8-eee3d4976f0e
                      name:
                        type: string
                        example: 'Considine LLC'
                      legal_name:
                        type: string
                        example: null
                        nullable: true
                      email:
                        type: string
                        example: ernie.nitzsche@ankunding.biz
                      phone:
                        type: string
                        example: null
                        nullable: true
                      address_line_1:
                        type: string
                        example: null
                        nullable: true
                      address_line_2:
                        type: string
                        example: null
                        nullable: true
                      city:
                        type: string
                        example: null
                        nullable: true
                      state:
                        type: string
                        example: null
                        nullable: true
                      postal_code:
                        type: string
                        example: null
                        nullable: true
                      country:
                        type: string
                        example: null
                        nullable: true
                      currency:
                        type: string
                        example: USD
                      tax_number:
                        type: string
                        example: null
                        nullable: true
                      logo_path:
                        type: string
                        example: null
                        nullable: true
                      invoice_prefix:
                        type: string
                        example: INV-
                      quote_prefix:
                        type: string
                        example: QUO-
                      invoice_layout:
                        type: string
                        example: classic
                      default_payment_terms:
                        type: integer
                        example: 30
                      default_hourly_rate:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_1:
                        type: string
                        example: null
                        nullable: true
                      default_tax_name_2:
                        type: string
                        example: null
                        nullable: true
                      default_tax_rate_2:
                        type: string
                        example: null
                        nullable: true
                      late_fee_type:
                        type: string
                        example: null
                        nullable: true
                      late_fee_value:
                        type: string
                        example: null
                        nullable: true
                      late_fee_days:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
      tags:
        - Settings
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                legal_name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: ashly64@example.com
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: v
                  nullable: true
                address_line_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: d
                  nullable: true
                address_line_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: l
                  nullable: true
                city:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                state:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                postal_code:
                  type: string
                  description: 'Must not be greater than 20 characters.'
                  example: ikhwaykcmyuwpwlv
                  nullable: true
                country:
                  type: string
                  description: 'Must be 2 characters.'
                  example: qw
                  nullable: true
                currency:
                  type: string
                  description: 'Must be 3 characters.'
                  example: rsi
                  nullable: true
                tax_number:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: t
                  nullable: true
                invoice_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: cpscql
                  nullable: true
                quote_prefix:
                  type: string
                  description: 'Must not be greater than 10 characters.'
                  example: dzsnrw
                  nullable: true
                default_payment_terms:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 365.'
                  example: 19
                  nullable: true
                default_hourly_rate:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 33
                  nullable: true
                default_tax_name_1:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: j
                  nullable: true
                default_tax_rate_1:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 17
                  nullable: true
                default_tax_name_2:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: v
                  nullable: true
                default_tax_rate_2:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 10000.'
                  example: 24
                  nullable: true
                invoice_layout:
                  type: string
                  description: ''
                  example: classic
                  enum:
                    - classic
                    - modern
                    - compact
                  nullable: true
  /api/settings/branding:
    get:
      summary: 'Get branding settings.'
      operationId: getBrandingSettings
      description: 'Returns the company logo path and default invoice template branding settings.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    logo_path: logos/1/logo.png
                    template:
                      id: 1
                      layout: modern
                      primary_color: '#1a1a2e'
                      secondary_color: '#1e40af'
                      accent_color: '#3b82f6'
                      font_family: Helvetica
                      show_logo: true
                      header_html: null
                      footer_html: null
                      custom_css: null
                properties:
                  data:
                    type: object
                    properties:
                      logo_path:
                        type: string
                        example: logos/1/logo.png
                      template:
                        type: object
                        properties:
                          id:
                            type: integer
                            example: 1
                          layout:
                            type: string
                            example: modern
                          primary_color:
                            type: string
                            example: '#1a1a2e'
                          secondary_color:
                            type: string
                            example: '#1e40af'
                          accent_color:
                            type: string
                            example: '#3b82f6'
                          font_family:
                            type: string
                            example: Helvetica
                          show_logo:
                            type: boolean
                            example: true
                          header_html:
                            type: string
                            example: null
                            nullable: true
                          footer_html:
                            type: string
                            example: null
                            nullable: true
                          custom_css:
                            type: string
                            example: null
                            nullable: true
      tags:
        - Settings
    put:
      summary: 'Update branding settings.'
      operationId: updateBrandingSettings
      description: 'Creates or updates the default invoice template for the company. HTML fields are sanitized.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1
                    layout: modern
                    primary_color: '#1a1a2e'
                    secondary_color: '#1e40af'
                    accent_color: '#3b82f6'
                    font_family: Helvetica
                    show_logo: true
                    header_html: null
                    footer_html: null
                    custom_css: null
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1
                      layout:
                        type: string
                        example: modern
                      primary_color:
                        type: string
                        example: '#1a1a2e'
                      secondary_color:
                        type: string
                        example: '#1e40af'
                      accent_color:
                        type: string
                        example: '#3b82f6'
                      font_family:
                        type: string
                        example: Helvetica
                      show_logo:
                        type: boolean
                        example: true
                      header_html:
                        type: string
                        example: null
                        nullable: true
                      footer_html:
                        type: string
                        example: null
                        nullable: true
                      custom_css:
                        type: string
                        example: null
                        nullable: true
      tags:
        - Settings
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                layout:
                  type: string
                  description: ''
                  example: modern
                  enum:
                    - classic
                    - modern
                    - compact
                  nullable: true
                primary_color:
                  type: string
                  description: 'Must not be greater than 7 characters.'
                  example: bngzmiy
                  nullable: true
                secondary_color:
                  type: string
                  description: 'Must not be greater than 7 characters.'
                  example: vdljnik
                  nullable: true
                accent_color:
                  type: string
                  description: 'Must not be greater than 7 characters.'
                  example: hwaykcm
                  nullable: true
                font_family:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'y'
                  nullable: true
                show_logo:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
                header_html:
                  type: string
                  description: 'Must not be greater than 5000 characters.'
                  example: u
                  nullable: true
                footer_html:
                  type: string
                  description: 'Must not be greater than 5000 characters.'
                  example: w
                  nullable: true
                custom_css:
                  type: string
                  description: 'Must not be greater than 5000 characters.'
                  example: p
                  nullable: true
  /api/settings/branding/logo:
    post:
      summary: 'Upload company logo.'
      operationId: uploadCompanyLogo
      description: 'Accepts a JPEG, PNG, GIF, or WebP image up to 2 MB. Replaces any existing logo.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    logo_path: logos/1/logo.png
                properties:
                  data:
                    type: object
                    properties:
                      logo_path:
                        type: string
                        example: logos/1/logo.png
      tags:
        - Settings
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                logo:
                  type: string
                  format: binary
                  description: 'The logo image file. Accepted: jpeg, png, gif, webp. Max 2 MB.'
              required:
                - logo
  /api/settings/late-fees:
    get:
      summary: 'Get late fee settings.'
      operationId: getLateFeeSettings
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    late_fee_type: percentage
                    late_fee_value: 150
                    late_fee_days: 30
                properties:
                  data:
                    type: object
                    properties:
                      late_fee_type:
                        type: string
                        example: percentage
                      late_fee_value:
                        type: integer
                        example: 150
                      late_fee_days:
                        type: integer
                        example: 30
      tags:
        - Settings
    put:
      summary: 'Update late fee settings.'
      operationId: updateLateFeeSettings
      description: "`late_fee_value` is stored in cents (flat) or basis points (percentage). `late_fee_days` is\nthe number of days past due before the fee applies."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    late_fee_type: percentage
                    late_fee_value: 150
                    late_fee_days: 30
                properties:
                  data:
                    type: object
                    properties:
                      late_fee_type:
                        type: string
                        example: percentage
                      late_fee_value:
                        type: integer
                        example: 150
                      late_fee_days:
                        type: integer
                        example: 30
      tags:
        - Settings
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                late_fee_type:
                  type: string
                  description: ''
                  example: flat
                  enum:
                    - percentage
                    - flat
                  nullable: true
                late_fee_value:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 27
                  nullable: true
                late_fee_days:
                  type: integer
                  description: 'Must be at least 0. Must not be greater than 90.'
                  example: 22
                  nullable: true
  /api/settings/reminders:
    get:
      summary: 'List payment reminders.'
      operationId: listPaymentReminders
      description: 'Returns all payment reminders for the current company ordered by reminder number.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      reminder_number: 1
                      days_offset: -3
                      subject: 'Invoice due soon'
                      body: 'Your invoice is due in 3 days.'
                      is_active: true
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        reminder_number: 1
                        days_offset: -3
                        subject: 'Invoice due soon'
                        body: 'Your invoice is due in 3 days.'
                        is_active: true
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        reminder_number:
                          type: integer
                          example: 1
                        days_offset:
                          type: integer
                          example: -3
                        subject:
                          type: string
                          example: 'Invoice due soon'
                        body:
                          type: string
                          example: 'Your invoice is due in 3 days.'
                        is_active:
                          type: boolean
                          example: true
      tags:
        - Settings
    post:
      summary: 'Create a payment reminder.'
      operationId: createAPaymentReminder
      description: "`days_offset` is relative to the due date: negative values send before due, positive values\nsend after due."
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 2
                    reminder_number: 2
                    days_offset: 7
                    subject: 'Invoice overdue'
                    body: 'Your invoice is 7 days overdue.'
                    is_active: true
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 2
                      reminder_number:
                        type: integer
                        example: 2
                      days_offset:
                        type: integer
                        example: 7
                      subject:
                        type: string
                        example: 'Invoice overdue'
                      body:
                        type: string
                        example: 'Your invoice is 7 days overdue.'
                      is_active:
                        type: boolean
                        example: true
      tags:
        - Settings
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                reminder_number:
                  type: integer
                  description: 'Must be at least 1. Must not be greater than 3.'
                  example: 1
                days_offset:
                  type: integer
                  description: 'Must be at least -30. Must not be greater than 90.'
                  example: 22
                subject:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: g
                  nullable: true
                body:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: z
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: false
                  nullable: true
              required:
                - reminder_number
                - days_offset
  '/api/settings/reminders/{reminder_id}':
    put:
      summary: 'Update a payment reminder.'
      operationId: updateAPaymentReminder
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 1
                    reminder_number: 1
                    days_offset: -3
                    subject: 'Invoice due soon'
                    body: 'Your invoice is due in 3 days.'
                    is_active: true
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 1
                      reminder_number:
                        type: integer
                        example: 1
                      days_offset:
                        type: integer
                        example: -3
                      subject:
                        type: string
                        example: 'Invoice due soon'
                      body:
                        type: string
                        example: 'Your invoice is due in 3 days.'
                      is_active:
                        type: boolean
                        example: true
      tags:
        - Settings
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                reminder_number:
                  type: integer
                  description: 'Must be at least 1. Must not be greater than 3.'
                  example: 1
                days_offset:
                  type: integer
                  description: 'Must be at least -30. Must not be greater than 90.'
                  example: 22
                subject:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: g
                  nullable: true
                body:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: z
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
    delete:
      summary: 'Delete a payment reminder.'
      operationId: deleteAPaymentReminder
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - Settings
    parameters:
      -
        in: path
        name: reminder_id
        description: 'The ID of the reminder.'
        example: 16
        required: true
        schema:
          type: integer
  /api/settings/bank-accounts:
    get:
      summary: 'List bank accounts.'
      operationId: listBankAccounts
      description: 'Returns all bank accounts for the current company ordered by `sort_order`. Not paginated.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 4
                      name: Primary
                      details: 'Quidem nostrum qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora. Voluptatem laboriosam praesentium quis adipisci.'
                      sort_order: 0
                      created_at: '2026-04-05T19:38:23.000000Z'
                      updated_at: '2026-04-05T19:38:23.000000Z'
                    -
                      id: 5
                      name: Primary
                      details: 'Corporis dolorem mollitia deleniti nemo odit quia officia. Dignissimos neque blanditiis odio.'
                      sort_order: 0
                      created_at: '2026-04-05T19:38:23.000000Z'
                      updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 4
                        name: Primary
                        details: 'Quidem nostrum qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora. Voluptatem laboriosam praesentium quis adipisci.'
                        sort_order: 0
                        created_at: '2026-04-05T19:38:23.000000Z'
                        updated_at: '2026-04-05T19:38:23.000000Z'
                      -
                        id: 5
                        name: Primary
                        details: 'Corporis dolorem mollitia deleniti nemo odit quia officia. Dignissimos neque blanditiis odio.'
                        sort_order: 0
                        created_at: '2026-04-05T19:38:23.000000Z'
                        updated_at: '2026-04-05T19:38:23.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 4
                        name:
                          type: string
                          example: Primary
                        details:
                          type: string
                          example: 'Quidem nostrum qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora. Voluptatem laboriosam praesentium quis adipisci.'
                        sort_order:
                          type: integer
                          example: 0
                        created_at:
                          type: string
                          example: '2026-04-05T19:38:23.000000Z'
                        updated_at:
                          type: string
                          example: '2026-04-05T19:38:23.000000Z'
      tags:
        - 'Bank Accounts'
    post:
      summary: 'Create a bank account.'
      operationId: createABankAccount
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 6
                    name: Primary
                    details: 'Velit et fugiat sunt nihil accusantium. Mollitia modi deserunt aut ab provident perspiciatis quo. Nostrum aut adipisci quidem nostrum. Commodi incidunt iure odit.'
                    sort_order: 0
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 6
                      name:
                        type: string
                        example: Primary
                      details:
                        type: string
                        example: 'Velit et fugiat sunt nihil accusantium. Mollitia modi deserunt aut ab provident perspiciatis quo. Nostrum aut adipisci quidem nostrum. Commodi incidunt iure odit.'
                      sort_order:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example: {  }
                properties: {  }
      tags:
        - 'Bank Accounts'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 100 characters.'
                  example: b
                details:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                sort_order:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
              required:
                - name
  '/api/settings/bank-accounts/{id}':
    get:
      summary: 'Show a bank account.'
      operationId: showABankAccount
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 7
                    name: Primary
                    details: 'Quidem nostrum qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora. Voluptatem laboriosam praesentium quis adipisci.'
                    sort_order: 0
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 7
                      name:
                        type: string
                        example: Primary
                      details:
                        type: string
                        example: 'Quidem nostrum qui commodi incidunt iure odit. Et modi ipsum nostrum omnis autem et consequatur. Dolores enim non facere tempora. Voluptatem laboriosam praesentium quis adipisci.'
                      sort_order:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
      tags:
        - 'Bank Accounts'
    put:
      summary: 'Update a bank account.'
      operationId: updateABankAccount
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 8
                    name: Primary
                    details: 'Velit et fugiat sunt nihil accusantium. Mollitia modi deserunt aut ab provident perspiciatis quo. Nostrum aut adipisci quidem nostrum. Commodi incidunt iure odit.'
                    sort_order: 0
                    created_at: '2026-04-05T19:38:23.000000Z'
                    updated_at: '2026-04-05T19:38:23.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 8
                      name:
                        type: string
                        example: Primary
                      details:
                        type: string
                        example: 'Velit et fugiat sunt nihil accusantium. Mollitia modi deserunt aut ab provident perspiciatis quo. Nostrum aut adipisci quidem nostrum. Commodi incidunt iure odit.'
                      sort_order:
                        type: integer
                        example: 0
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:23.000000Z'
      tags:
        - 'Bank Accounts'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'Must not be greater than 100 characters.'
                  example: b
                details:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: 'n'
                  nullable: true
                sort_order:
                  type: integer
                  description: 'Must be at least 0.'
                  example: 84
                  nullable: true
              required:
                - name
    delete:
      summary: 'Delete a bank account.'
      operationId: deleteABankAccount
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Bank Accounts'
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the bank account.'
        example: 1
        required: true
        schema:
          type: integer
  /api/settings/freshbooks/callback:
    get:
      summary: 'FreshBooks OAuth callback.'
      operationId: freshBooksOAuthCallback
      description: "Handles the authorization code callback from FreshBooks. Exchanges the code for access\ntokens, fetches the FreshBooks identity, and syncs company settings. Redirects to the\nfrontend settings page on success."
      parameters:
        -
          in: query
          name: code
          description: 'Authorization code from FreshBooks.'
          example: authcode123
          required: true
          schema:
            type: string
            description: 'Authorization code from FreshBooks.'
            example: authcode123
      responses:
        302:
          description: 'Redirect to settings on success'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        400:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      message: 'Missing authorization code or session cookie. Please try connecting again.'
                    properties:
                      message:
                        type: string
                        example: 'Missing authorization code or session cookie. Please try connecting again.'
                  -
                    description: ''
                    type: object
                    example:
                      message: 'Missing authorization code or session cookie. Please try connecting again.'
                    properties:
                      message:
                        type: string
                        example: 'Missing authorization code or session cookie. Please try connecting again.'
        502:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Failed to exchange code for tokens.'
                properties:
                  message:
                    type: string
                    example: 'Failed to exchange code for tokens.'
      tags:
        - Imports
      security: []
  /api/settings/freshbooks/connect:
    get:
      summary: 'Initiate FreshBooks OAuth.'
      operationId: initiateFreshBooksOAuth
      description: "Redirects the user to FreshBooks' OAuth authorization page. Credentials must be saved first.\nIdentity is preserved via a signed cookie (FreshBooks does not support state parameter)."
      parameters:
        -
          in: query
          name: company_id
          description: 'The company to import into.'
          example: 1
          required: true
          schema:
            type: integer
            description: 'The company to import into.'
            example: 1
      responses:
        302:
          description: 'Redirect to FreshBooks'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Imports
  /api/settings/freshbooks/credentials:
    post:
      summary: 'Save FreshBooks OAuth credentials.'
      operationId: saveFreshBooksOAuthCredentials
      description: "Stores the FreshBooks app client ID and secret for the current user/company. Required before\ninitiating the OAuth flow."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Credentials saved'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Credentials saved'
      tags:
        - Imports
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: 'The FreshBooks app client ID.'
                  example: abc123
                client_secret:
                  type: string
                  description: 'The FreshBooks app client secret.'
                  example: secret456
              required:
                - client_id
                - client_secret
  /api/settings/freshbooks/preview:
    get:
      summary: 'Preview FreshBooks import counts.'
      operationId: previewFreshBooksImportCounts
      description: "Fetches resource counts from FreshBooks (clients, invoices, etc.) without importing. Updates\nthe import status to `previewing`."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    clients: 42
                    invoices: 210
                    payments: 185
                    expenses: 67
                properties:
                  data:
                    type: object
                    properties:
                      clients:
                        type: integer
                        example: 42
                      invoices:
                        type: integer
                        example: 210
                      payments:
                        type: integer
                        example: 185
                      expenses:
                        type: integer
                        example: 67
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'FreshBooks is not connected.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'FreshBooks is not connected.'
      tags:
        - Imports
  /api/settings/freshbooks/import:
    post:
      summary: 'Start FreshBooks import.'
      operationId: startFreshBooksImport
      description: "Queues the import job for the connected FreshBooks account. Optionally restrict to specific\nresource types. Returns 409 if an import is already in progress."
      parameters: []
      responses:
        202:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Import started'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Import started'
        409:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Import is already in progress.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Import is already in progress.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'FreshBooks is not connected.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'FreshBooks is not connected.'
      tags:
        - Imports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                selected_resources:
                  type: array
                  description: 'Optional list of resource types to import. Valid values depend on FreshBooksImportContext.'
                  example:
                    - clients
                    - invoices
                  items:
                    type: string
                reimport_existing:
                  type: boolean
                  description: 'Whether to overwrite previously imported records.'
                  example: false
                  nullable: true
  /api/settings/freshbooks/status:
    get:
      summary: 'Get FreshBooks import status.'
      operationId: getFreshBooksImportStatus
      description: "Returns the current state of the import record for the authenticated user and company.\nReturns `null` data if no import record exists."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      data:
                        status: importing
                        progress:
                          clients: 42
                          invoices: 0
                        preview_data: null
                        error_message: null
                        started_at: '2026-04-05T08:00:00+00:00'
                        completed_at: null
                        has_credentials: true
                        has_tokens: true
                        freshbooks_account_id: ABC123
                        selected_resources:
                          - clients
                          - invoices
                    properties:
                      data:
                        type: object
                        properties:
                          status:
                            type: string
                            example: importing
                          progress:
                            type: object
                            properties:
                              clients:
                                type: integer
                                example: 42
                              invoices:
                                type: integer
                                example: 0
                          preview_data:
                            type: string
                            example: null
                            nullable: true
                          error_message:
                            type: string
                            example: null
                            nullable: true
                          started_at:
                            type: string
                            example: '2026-04-05T08:00:00+00:00'
                          completed_at:
                            type: string
                            example: null
                            nullable: true
                          has_credentials:
                            type: boolean
                            example: true
                          has_tokens:
                            type: boolean
                            example: true
                          freshbooks_account_id:
                            type: string
                            example: ABC123
                          selected_resources:
                            type: array
                            example:
                              - clients
                              - invoices
                            items:
                              type: string
                  -
                    description: 'No import record'
                    type: object
                    example:
                      data: null
                    properties:
                      data:
                        type: string
                        example: null
                        nullable: true
      tags:
        - Imports
  /api/settings/freshbooks/reset:
    post:
      summary: 'Reset import to preview state.'
      operationId: resetImportToPreviewState
      description: "Clears any in-progress or errored import so a new import can be started from the preview\nstep."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Ready for new import'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Ready for new import'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'FreshBooks is not connected.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'FreshBooks is not connected.'
      tags:
        - Imports
  /api/settings/freshbooks/disconnect:
    post:
      summary: 'Disconnect FreshBooks.'
      operationId: disconnectFreshBooks
      description: "Clears stored OAuth tokens and account identifiers from the import record. The credentials\n(client ID/secret) are preserved."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Disconnected from FreshBooks.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Disconnected from FreshBooks.'
      tags:
        - Imports
  /api/settings/stripe/callback:
    get:
      summary: 'Stripe Connect OAuth callback.'
      operationId: stripeConnectOAuthCallback
      description: "Handles the OAuth callback from Stripe. Exchanges the authorization code for tokens, stores\nthe connected account ID on the company, then redirects to the frontend settings page."
      parameters:
        -
          in: query
          name: code
          description: 'Authorization code from Stripe.'
          example: ac_xxx
          required: true
          schema:
            type: string
            description: 'Authorization code from Stripe.'
            example: ac_xxx
        -
          in: query
          name: state
          description: 'Signed state parameter issued during connect.'
          example: base64encodedstate
          required: true
          schema:
            type: string
            description: 'Signed state parameter issued during connect.'
            example: base64encodedstate
      responses:
        302:
          description: 'Redirect to settings on success'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        400:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      message: 'Missing authorization code or state. Please try connecting again.'
                    properties:
                      message:
                        type: string
                        example: 'Missing authorization code or state. Please try connecting again.'
                  -
                    description: ''
                    type: object
                    example:
                      message: 'Invalid session. Please try connecting again.'
                    properties:
                      message:
                        type: string
                        example: 'Invalid session. Please try connecting again.'
        502:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Failed to connect Stripe account.'
                properties:
                  message:
                    type: string
                    example: 'Failed to connect Stripe account.'
      tags:
        - 'Stripe Connect'
      security: []
  /api/settings/stripe/connect:
    get:
      summary: 'Initiate Stripe Connect OAuth.'
      operationId: initiateStripeConnectOAuth
      description: "Redirects the user to Stripe's OAuth authorization page. Requires `company_id` as a query\nparameter. The user must have access to the specified company."
      parameters:
        -
          in: query
          name: company_id
          description: 'The company to connect Stripe to.'
          example: 1
          required: true
          schema:
            type: integer
            description: 'The company to connect Stripe to.'
            example: 1
      responses:
        302:
          description: 'Redirect to Stripe'
          content:
            text/plain:
              schema:
                type: string
                example: ''
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - 'Stripe Connect'
  /api/settings/stripe/status:
    get:
      summary: 'Get Stripe Connect status.'
      operationId: getStripeConnectStatus
      description: "Returns the connection status of the company's Stripe Connect account. Fetches live status\nfrom Stripe and syncs it locally; falls back to cached values if Stripe is unreachable."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: Connected
                    type: object
                    example:
                      data:
                        connected: true
                        account_name: 'Acme Corp'
                        payouts_enabled: true
                        charges_enabled: true
                        connected_at: '2026-01-15T10:00:00+00:00'
                    properties:
                      data:
                        type: object
                        properties:
                          connected:
                            type: boolean
                            example: true
                          account_name:
                            type: string
                            example: 'Acme Corp'
                          payouts_enabled:
                            type: boolean
                            example: true
                          charges_enabled:
                            type: boolean
                            example: true
                          connected_at:
                            type: string
                            example: '2026-01-15T10:00:00+00:00'
                  -
                    description: 'Not connected'
                    type: object
                    example:
                      data:
                        connected: false
                    properties:
                      data:
                        type: object
                        properties:
                          connected:
                            type: boolean
                            example: false
      tags:
        - 'Stripe Connect'
  /api/settings/stripe/disconnect:
    post:
      summary: 'Disconnect Stripe Connect.'
      operationId: disconnectStripeConnect
      description: "Deauthorizes the connected Stripe account and clears the connection from the company record.\nProceeds even if the Stripe deauthorization API call fails."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    message: 'Stripe account disconnected.'
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        example: 'Stripe account disconnected.'
      tags:
        - 'Stripe Connect'
  /api/api-tokens:
    get:
      summary: 'List API tokens.'
      operationId: listAPITokens
      description: "Returns all personal access tokens for the authenticated user. The token value is never\nreturned after creation."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      name: 'My Token'
                      last_used_at: '2026-04-01T10:00:00Z'
                      created_at: '2026-03-01T10:00:00Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        name: 'My Token'
                        last_used_at: '2026-04-01T10:00:00Z'
                        created_at: '2026-03-01T10:00:00Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: 'My Token'
                        last_used_at:
                          type: string
                          example: '2026-04-01T10:00:00Z'
                        created_at:
                          type: string
                          example: '2026-03-01T10:00:00Z'
      tags:
        - 'API Tokens'
    post:
      summary: 'Create an API token.'
      operationId: createAnAPIToken
      description: "Requires a Pro plan. The `token` field is only returned on creation and cannot be retrieved\nagain."
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 2
                    name: 'CI Deploy Token'
                    token: 1|abc123plaintext
                    created_at: '2026-04-05T08:00:00Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 2
                      name:
                        type: string
                        example: 'CI Deploy Token'
                      token:
                        type: string
                        example: 1|abc123plaintext
                      created_at:
                        type: string
                        example: '2026-04-05T08:00:00Z'
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'API access requires a Pro plan. Please upgrade.'
                properties:
                  message:
                    type: string
                    example: 'API access requires a Pro plan. Please upgrade.'
      tags:
        - 'API Tokens'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'A descriptive name for the token.'
                  example: 'CI Deploy Token'
              required:
                - name
  '/api/api-tokens/{tokenId}':
    delete:
      summary: 'Revoke an API token.'
      operationId: revokeAnAPIToken
      description: ''
      parameters: []
      responses:
        204:
          description: 'No content'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'API Tokens'
    parameters:
      -
        in: path
        name: tokenId
        description: ''
        example: architecto
        required: true
        schema:
          type: string
  '/api/invitations/{token}/details':
    get:
      summary: 'Get invitation details.'
      operationId: getInvitationDetails
      description: "Returns the company name, role, invitee email, and inviter name for the given invitation\ntoken. Returns 404 if the token is not found, 410 if expired, and 422 if already accepted."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    company_name: 'Acme Corp'
                    role: member
                    email: jane@example.com
                    inviter: 'John Smith'
                properties:
                  data:
                    type: object
                    properties:
                      company_name:
                        type: string
                        example: 'Acme Corp'
                      role:
                        type: string
                        example: member
                      email:
                        type: string
                        example: jane@example.com
                      inviter:
                        type: string
                        example: 'John Smith'
        410:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This invitation has expired.'
                properties:
                  message:
                    type: string
                    example: 'This invitation has expired.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This invitation has already been accepted.'
                properties:
                  message:
                    type: string
                    example: 'This invitation has already been accepted.'
      tags:
        - Invitations
      security: []
    parameters:
      -
        in: path
        name: token
        description: 'The invitation token.'
        example: abc123token
        required: true
        schema:
          type: string
  '/api/invitations/{token}/accept':
    post:
      summary: 'Accept an invitation.'
      operationId: acceptAnInvitation
      description: "Adds the authenticated user to the company with the invited role and marks the invitation\nas accepted. Runs inside a transaction. Returns the company ID on success."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      message: 'Invitation accepted.'
                      data:
                        company_id: 5
                    properties:
                      message:
                        type: string
                        example: 'Invitation accepted.'
                      data:
                        type: object
                        properties:
                          company_id:
                            type: integer
                            example: 5
                  -
                    description: 'Already a member'
                    type: object
                    example:
                      message: 'You are already a member of this company.'
                      data:
                        company_id: 5
                    properties:
                      message:
                        type: string
                        example: 'You are already a member of this company.'
                      data:
                        type: object
                        properties:
                          company_id:
                            type: integer
                            example: 5
        410:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This invitation has expired.'
                properties:
                  message:
                    type: string
                    example: 'This invitation has expired.'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This invitation has already been accepted.'
                properties:
                  message:
                    type: string
                    example: 'This invitation has already been accepted.'
      tags:
        - Invitations
    parameters:
      -
        in: path
        name: token
        description: 'The invitation token.'
        example: abc123token
        required: true
        schema:
          type: string
  '/api/portal/invoices/{uuid}':
    get:
      summary: 'Get invoice for client portal.'
      operationId: getInvoiceForClientPortal
      description: "Public endpoint accessed via invoice UUID. Marks the invoice as viewed on first access.\nAlso returns Stripe payment availability and bank account details if configured."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 42
                    invoice_number: INV-0042
                    status: sent
                    total: 150000
                    amount_due: 150000
                    currency: USD
                  payment_available: true
                  bank_details: null
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 42
                      invoice_number:
                        type: string
                        example: INV-0042
                      status:
                        type: string
                        example: sent
                      total:
                        type: integer
                        example: 150000
                      amount_due:
                        type: integer
                        example: 150000
                      currency:
                        type: string
                        example: USD
                  payment_available:
                    type: boolean
                    example: true
                  bank_details:
                    type: string
                    example: null
                    nullable: true
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The invoice UUID.'
        example: 550e8400-e29b-41d4-a716-446655440000
        required: true
        schema:
          type: string
  '/api/portal/invoices/{uuid}/pdf':
    get:
      summary: 'Download invoice PDF.'
      operationId: downloadInvoicePDF
      description: 'Returns the invoice as a PDF file. Public endpoint accessed via UUID.'
      parameters: []
      responses:
        200:
          description: 'PDF file'
          content:
            application/json:
              schema:
                type: object
                example:
                  Content-Type: application/pdf
                properties:
                  Content-Type:
                    type: string
                    example: application/pdf
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The invoice UUID.'
        example: 550e8400-e29b-41d4-a716-446655440000
        required: true
        schema:
          type: string
  '/api/portal/quotes/{uuid}':
    get:
      summary: 'Get quote for client portal.'
      operationId: getQuoteForClientPortal
      description: 'Public endpoint accessed via quote UUID. Marks the quote as viewed on first access.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 151
                    uuid: 13fb884a-24bf-4790-9731-a88368d2068a
                    client_id: 125
                    quote_number: QUO-66650
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:13.000000Z'
                    updated_at: '2026-04-05T19:38:13.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 151
                      uuid:
                        type: string
                        example: 13fb884a-24bf-4790-9731-a88368d2068a
                      client_id:
                        type: integer
                        example: 125
                      quote_number:
                        type: string
                        example: QUO-66650
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The quote UUID.'
        example: 550e8400-e29b-41d4-a716-446655440001
        required: true
        schema:
          type: string
  '/api/portal/quotes/{uuid}/pdf':
    get:
      summary: 'Download quote PDF.'
      operationId: downloadQuotePDF
      description: 'Returns the quote as a PDF file. Public endpoint accessed via UUID.'
      parameters: []
      responses:
        200:
          description: 'PDF file'
          content:
            application/json:
              schema:
                type: object
                example:
                  Content-Type: application/pdf
                properties:
                  Content-Type:
                    type: string
                    example: application/pdf
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The quote UUID.'
        example: 550e8400-e29b-41d4-a716-446655440001
        required: true
        schema:
          type: string
  '/api/portal/quotes/{uuid}/accept':
    post:
      summary: 'Accept a quote.'
      operationId: acceptAQuote
      description: 'Transitions the quote to the accepted status. Public endpoint accessed via UUID.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 152
                    uuid: 2398d4ba-97d1-45dc-9fa1-fa2af7b601cc
                    client_id: 126
                    quote_number: QUO-77300
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:13.000000Z'
                    updated_at: '2026-04-05T19:38:13.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 152
                      uuid:
                        type: string
                        example: 2398d4ba-97d1-45dc-9fa1-fa2af7b601cc
                      client_id:
                        type: integer
                        example: 126
                      quote_number:
                        type: string
                        example: QUO-77300
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Quote cannot be accepted in its current status.'
                properties:
                  message:
                    type: string
                    example: 'Quote cannot be accepted in its current status.'
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The quote UUID.'
        example: 550e8400-e29b-41d4-a716-446655440001
        required: true
        schema:
          type: string
  '/api/portal/quotes/{uuid}/decline':
    post:
      summary: 'Decline a quote.'
      operationId: declineAQuote
      description: 'Transitions the quote to the declined status. Public endpoint accessed via UUID.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 153
                    uuid: 94349ce5-6058-456d-9288-03f3dc8e70cc
                    client_id: 127
                    quote_number: QUO-10778
                    status: draft
                    is_archived: false
                    status_label: Draft
                    status_color: gray
                    issue_date: '2026-04-05'
                    expiry_date: '2026-05-05'
                    currency: USD
                    subtotal: 0
                    tax_total: 0
                    discount_type: null
                    discount_value: null
                    discount_total: 0
                    total: 0
                    notes: null
                    terms: null
                    footer: null
                    sent_at: null
                    viewed_at: null
                    accepted_at: null
                    declined_at: null
                    converted_to_invoice_id: null
                    converted_to_project_id: null
                    pdf_path: null
                    created_at: '2026-04-05T19:38:13.000000Z'
                    updated_at: '2026-04-05T19:38:13.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 153
                      uuid:
                        type: string
                        example: 94349ce5-6058-456d-9288-03f3dc8e70cc
                      client_id:
                        type: integer
                        example: 127
                      quote_number:
                        type: string
                        example: QUO-10778
                      status:
                        type: string
                        example: draft
                      is_archived:
                        type: boolean
                        example: false
                      status_label:
                        type: string
                        example: Draft
                      status_color:
                        type: string
                        example: gray
                      issue_date:
                        type: string
                        example: '2026-04-05'
                      expiry_date:
                        type: string
                        example: '2026-05-05'
                      currency:
                        type: string
                        example: USD
                      subtotal:
                        type: integer
                        example: 0
                      tax_total:
                        type: integer
                        example: 0
                      discount_type:
                        type: string
                        example: null
                        nullable: true
                      discount_value:
                        type: string
                        example: null
                        nullable: true
                      discount_total:
                        type: integer
                        example: 0
                      total:
                        type: integer
                        example: 0
                      notes:
                        type: string
                        example: null
                        nullable: true
                      terms:
                        type: string
                        example: null
                        nullable: true
                      footer:
                        type: string
                        example: null
                        nullable: true
                      sent_at:
                        type: string
                        example: null
                        nullable: true
                      viewed_at:
                        type: string
                        example: null
                        nullable: true
                      accepted_at:
                        type: string
                        example: null
                        nullable: true
                      declined_at:
                        type: string
                        example: null
                        nullable: true
                      converted_to_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      converted_to_project_id:
                        type: string
                        example: null
                        nullable: true
                      pdf_path:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
                      updated_at:
                        type: string
                        example: '2026-04-05T19:38:13.000000Z'
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Quote cannot be declined in its current status.'
                properties:
                  message:
                    type: string
                    example: 'Quote cannot be declined in its current status.'
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The quote UUID.'
        example: 550e8400-e29b-41d4-a716-446655440001
        required: true
        schema:
          type: string
  '/api/portal/invoices/{uuid}/checkout':
    post:
      summary: 'Initiate portal payment.'
      operationId: initiatePortalPayment
      description: "Creates a Stripe Checkout session for the invoice (using the company's Connect account) or\nreturns bank transfer details if Stripe is not connected. Public endpoint accessed via UUID."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: 'Stripe checkout'
                    type: object
                    example:
                      data:
                        checkout_url: 'https://checkout.stripe.com/pay/cs_live_xxx'
                    properties:
                      data:
                        type: object
                        properties:
                          checkout_url:
                            type: string
                            example: 'https://checkout.stripe.com/pay/cs_live_xxx'
                  -
                    description: 'Bank transfer'
                    type: object
                    example:
                      data:
                        payment_method: bank_details
                        bank_accounts:
                          -
                            name: 'Main Account'
                            details: 'BSB 123-456, Account 987654321'
                        reference: INV-0042
                        amount: 150000
                        currency: USD
                    properties:
                      data:
                        type: object
                        properties:
                          payment_method:
                            type: string
                            example: bank_details
                          bank_accounts:
                            type: array
                            example:
                              -
                                name: 'Main Account'
                                details: 'BSB 123-456, Account 987654321'
                            items:
                              type: object
                              properties:
                                name:
                                  type: string
                                  example: 'Main Account'
                                details:
                                  type: string
                                  example: 'BSB 123-456, Account 987654321'
                          reference:
                            type: string
                            example: INV-0042
                          amount:
                            type: integer
                            example: 150000
                          currency:
                            type: string
                            example: USD
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Invoice is not payable.'
                properties:
                  message:
                    type: string
                    example: 'Invoice is not payable.'
        502:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Payment service unavailable. Please try again later.'
                properties:
                  message:
                    type: string
                    example: 'Payment service unavailable. Please try again later.'
      tags:
        - 'Client Portal'
      security: []
    parameters:
      -
        in: path
        name: uuid
        description: 'The invoice UUID.'
        example: 550e8400-e29b-41d4-a716-446655440000
        required: true
        schema:
          type: string
  /api/dashboard/stats:
    get:
      summary: 'Get dashboard stats.'
      operationId: getDashboardStats
      description: "Returns outstanding and overdue invoice totals (by currency), plus unbilled time entry\nhours and estimated value for the current company."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    outstanding_by_currency:
                      USD: 250000
                    overdue_by_currency:
                      USD: 75000
                    unbilled_hours: 12.5
                    unbilled_amount: 187500
                properties:
                  data:
                    type: object
                    properties:
                      outstanding_by_currency:
                        type: object
                        properties:
                          USD:
                            type: integer
                            example: 250000
                      overdue_by_currency:
                        type: object
                        properties:
                          USD:
                            type: integer
                            example: 75000
                      unbilled_hours:
                        type: number
                        example: 12.5
                      unbilled_amount:
                        type: integer
                        example: 187500
      tags:
        - Dashboard
  /api/dashboard/revenue-chart:
    get:
      summary: 'Get revenue chart data.'
      operationId: getRevenueChartData
      description: 'Returns monthly revenue grouped by currency for the last 12 months.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      month: 'May 2025'
                      revenue_by_currency:
                        USD: 120000
                    -
                      month: 'Apr 2026'
                      revenue_by_currency:
                        USD: 180000
                properties:
                  data:
                    type: array
                    example:
                      -
                        month: 'May 2025'
                        revenue_by_currency:
                          USD: 120000
                      -
                        month: 'Apr 2026'
                        revenue_by_currency:
                          USD: 180000
                    items:
                      type: object
                      properties:
                        month:
                          type: string
                          example: 'May 2025'
                        revenue_by_currency:
                          type: object
                          properties:
                            USD:
                              type: integer
                              example: 120000
      tags:
        - Dashboard
  /api/dashboard/recent-activity:
    get:
      summary: 'Get recent activity.'
      operationId: getRecentActivity
      description: 'Returns the 10 most recently updated non-cancelled, non-archived invoices.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      type: invoice
                      id: 42
                      description: 'Invoice INV-0042 to Acme Corp'
                      status: sent
                      amount: 150000
                      date: '2026-04-04T09:00:00Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        type: invoice
                        id: 42
                        description: 'Invoice INV-0042 to Acme Corp'
                        status: sent
                        amount: 150000
                        date: '2026-04-04T09:00:00Z'
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                          example: invoice
                        id:
                          type: integer
                          example: 42
                        description:
                          type: string
                          example: 'Invoice INV-0042 to Acme Corp'
                        status:
                          type: string
                          example: sent
                        amount:
                          type: integer
                          example: 150000
                        date:
                          type: string
                          example: '2026-04-04T09:00:00Z'
      tags:
        - Dashboard
  /api/dashboard/aging:
    get:
      summary: 'Get accounts receivable aging.'
      operationId: getAccountsReceivableAging
      description: "Returns outstanding invoice totals bucketed by age (0-30, 31-60, 61-90, 91+ days), grouped\nby currency."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    USD:
                      overdue_total: 75000
                      outstanding_total: 175000
                      total: 250000
                      buckets:
                        -
                          label: '0-30 Days'
                          amount: 100000
                        -
                          label: '31-60 Days'
                          amount: 75000
                        -
                          label: '61-90 Days'
                          amount: 50000
                        -
                          label: '91+ Days'
                          amount: 25000
                properties:
                  data:
                    type: object
                    properties:
                      USD:
                        type: object
                        properties:
                          overdue_total:
                            type: integer
                            example: 75000
                          outstanding_total:
                            type: integer
                            example: 175000
                          total:
                            type: integer
                            example: 250000
                          buckets:
                            type: array
                            example:
                              -
                                label: '0-30 Days'
                                amount: 100000
                              -
                                label: '31-60 Days'
                                amount: 75000
                              -
                                label: '61-90 Days'
                                amount: 50000
                              -
                                label: '91+ Days'
                                amount: 25000
                            items:
                              type: object
                              properties:
                                label:
                                  type: string
                                  example: '0-30 Days'
                                amount:
                                  type: integer
                                  example: 100000
      tags:
        - Dashboard
  /api/dashboard/unbilled-by-client:
    get:
      summary: 'Get unbilled hours by client.'
      operationId: getUnbilledHoursByClient
      description: "Returns the top 10 clients with unbilled billable time entries, ordered by total unbilled\nhours."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    total_hours: 34.5
                    clients:
                      -
                        client_id: 7
                        client_name: 'Acme Corp'
                        hours: 18.0
                        seconds: 64800
                      -
                        client_id: 3
                        client_name: Globex
                        hours: 16.5
                        seconds: 59400
                properties:
                  data:
                    type: object
                    properties:
                      total_hours:
                        type: number
                        example: 34.5
                      clients:
                        type: array
                        example:
                          -
                            client_id: 7
                            client_name: 'Acme Corp'
                            hours: 18
                            seconds: 64800
                          -
                            client_id: 3
                            client_name: Globex
                            hours: 16.5
                            seconds: 59400
                        items:
                          type: object
                          properties:
                            client_id:
                              type: integer
                              example: 7
                            client_name:
                              type: string
                              example: 'Acme Corp'
                            hours:
                              type: number
                              example: 18.0
                            seconds:
                              type: integer
                              example: 64800
      tags:
        - Dashboard
  /api/dashboard/revenue-by-client:
    get:
      summary: 'Get revenue by client.'
      operationId: getRevenueByClient
      description: 'Returns the top 10 clients by total invoiced amount (year to date), grouped by currency.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    year: 2026
                    clients:
                      -
                        client_id: 7
                        client_name: 'Acme Corp'
                        currency: USD
                        total: 480000
                      -
                        client_id: 3
                        client_name: Globex
                        currency: USD
                        total: 210000
                properties:
                  data:
                    type: object
                    properties:
                      year:
                        type: integer
                        example: 2026
                      clients:
                        type: array
                        example:
                          -
                            client_id: 7
                            client_name: 'Acme Corp'
                            currency: USD
                            total: 480000
                          -
                            client_id: 3
                            client_name: Globex
                            currency: USD
                            total: 210000
                        items:
                          type: object
                          properties:
                            client_id:
                              type: integer
                              example: 7
                            client_name:
                              type: string
                              example: 'Acme Corp'
                            currency:
                              type: string
                              example: USD
                            total:
                              type: integer
                              example: 480000
      tags:
        - Dashboard
  /api/reports/profit-loss:
    get:
      summary: 'Profit and loss report.'
      operationId: profitAndLossReport
      description: "Returns monthly invoiced/collected revenue and expenses for the given date range. All\nmonetary values are in cents."
      parameters:
        -
          in: query
          name: start_date
          description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
            example: '2026-01-01'
        -
          in: query
          name: end_date
          description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
          example: '2026-12-31'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
            example: '2026-12-31'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  period:
                    start: '2026-01-01'
                    end: '2026-12-31'
                  revenue:
                    invoiced: 600000
                    collected: 480000
                    by_month:
                      -
                        month: 'Jan 2026'
                        month_key: 2026-01
                        invoiced: 50000
                        collected: 40000
                        expenses: 10000
                        profit: 30000
                  summary:
                    total_invoiced: 600000
                    total_collected: 480000
                    outstanding: 120000
                    total_expenses: 60000
                    net_profit: 420000
                properties:
                  period:
                    type: object
                    properties:
                      start:
                        type: string
                        example: '2026-01-01'
                      end:
                        type: string
                        example: '2026-12-31'
                  revenue:
                    type: object
                    properties:
                      invoiced:
                        type: integer
                        example: 600000
                      collected:
                        type: integer
                        example: 480000
                      by_month:
                        type: array
                        example:
                          -
                            month: 'Jan 2026'
                            month_key: 2026-01
                            invoiced: 50000
                            collected: 40000
                            expenses: 10000
                            profit: 30000
                        items:
                          type: object
                          properties:
                            month:
                              type: string
                              example: 'Jan 2026'
                            month_key:
                              type: string
                              example: 2026-01
                            invoiced:
                              type: integer
                              example: 50000
                            collected:
                              type: integer
                              example: 40000
                            expenses:
                              type: integer
                              example: 10000
                            profit:
                              type: integer
                              example: 30000
                  summary:
                    type: object
                    properties:
                      total_invoiced:
                        type: integer
                        example: 600000
                      total_collected:
                        type: integer
                        example: 480000
                      outstanding:
                        type: integer
                        example: 120000
                      total_expenses:
                        type: integer
                        example: 60000
                      net_profit:
                        type: integer
                        example: 420000
      tags:
        - Reports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:23'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
  /api/reports/account-aging:
    get:
      summary: 'Accounts receivable aging report.'
      operationId: accountsReceivableAgingReport
      description: "Returns outstanding invoice amounts bucketed by age across all payable invoices, with a\nper-client breakdown."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  buckets:
                    -
                      label: Current
                      range: '0-30 days'
                      amount: 100000
                      count: 5
                    -
                      label: '31-60 days'
                      range: '31-60 days'
                      amount: 50000
                      count: 2
                    -
                      label: '61-90 days'
                      range: '61-90 days'
                      amount: 25000
                      count: 1
                    -
                      label: '90+ days'
                      range: '90+ days'
                      amount: 10000
                      count: 1
                  total_outstanding: 185000
                  clients:
                    -
                      client_id: 7
                      client_name: 'Acme Corp'
                      current: 100000
                      days_31_60: 50000
                      days_61_90: 0
                      days_90_plus: 0
                      total: 150000
                properties:
                  buckets:
                    type: array
                    example:
                      -
                        label: Current
                        range: '0-30 days'
                        amount: 100000
                        count: 5
                      -
                        label: '31-60 days'
                        range: '31-60 days'
                        amount: 50000
                        count: 2
                      -
                        label: '61-90 days'
                        range: '61-90 days'
                        amount: 25000
                        count: 1
                      -
                        label: '90+ days'
                        range: '90+ days'
                        amount: 10000
                        count: 1
                    items:
                      type: object
                      properties:
                        label:
                          type: string
                          example: Current
                        range:
                          type: string
                          example: '0-30 days'
                        amount:
                          type: integer
                          example: 100000
                        count:
                          type: integer
                          example: 5
                  total_outstanding:
                    type: integer
                    example: 185000
                  clients:
                    type: array
                    example:
                      -
                        client_id: 7
                        client_name: 'Acme Corp'
                        current: 100000
                        days_31_60: 50000
                        days_61_90: 0
                        days_90_plus: 0
                        total: 150000
                    items:
                      type: object
                      properties:
                        client_id:
                          type: integer
                          example: 7
                        client_name:
                          type: string
                          example: 'Acme Corp'
                        current:
                          type: integer
                          example: 100000
                        days_31_60:
                          type: integer
                          example: 50000
                        days_61_90:
                          type: integer
                          example: 0
                        days_90_plus:
                          type: integer
                          example: 0
                        total:
                          type: integer
                          example: 150000
      tags:
        - Reports
  /api/reports/tax-summary:
    get:
      summary: 'Tax summary report.'
      operationId: taxSummaryReport
      description: "Returns tax collected per tax name/rate combination for the given date range. Amounts in\ncents, tax rates in basis points (e.g. 1500 = 15%)."
      parameters:
        -
          in: query
          name: start_date
          description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
            example: '2026-01-01'
        -
          in: query
          name: end_date
          description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
          example: '2026-12-31'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
            example: '2026-12-31'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  period:
                    start: '2026-01-01'
                    end: '2026-12-31'
                  taxes:
                    -
                      tax_name: GST
                      tax_rate: 1500
                      taxable_amount: 400000
                      tax_collected: 60000
                      invoice_count: 12
                  total_tax_collected: 60000
                properties:
                  period:
                    type: object
                    properties:
                      start:
                        type: string
                        example: '2026-01-01'
                      end:
                        type: string
                        example: '2026-12-31'
                  taxes:
                    type: array
                    example:
                      -
                        tax_name: GST
                        tax_rate: 1500
                        taxable_amount: 400000
                        tax_collected: 60000
                        invoice_count: 12
                    items:
                      type: object
                      properties:
                        tax_name:
                          type: string
                          example: GST
                        tax_rate:
                          type: integer
                          example: 1500
                        taxable_amount:
                          type: integer
                          example: 400000
                        tax_collected:
                          type: integer
                          example: 60000
                        invoice_count:
                          type: integer
                          example: 12
                  total_tax_collected:
                    type: integer
                    example: 60000
      tags:
        - Reports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:23'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
  /api/reports/team-utilization:
    get:
      summary: 'Team utilization report.'
      operationId: teamUtilizationReport
      description: "Returns billable vs non-billable hours and utilization rate per team member for the given\ndate range."
      parameters:
        -
          in: query
          name: start_date
          description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
            example: '2026-01-01'
        -
          in: query
          name: end_date
          description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
          example: '2026-12-31'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
            example: '2026-12-31'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  period:
                    start: '2026-01-01'
                    end: '2026-12-31'
                  members:
                    -
                      user_id: 1
                      name: 'Jane Smith'
                      total_hours: 160.0
                      billable_hours: 128.0
                      non_billable_hours: 32.0
                      utilization_rate: 80.0
                      billable_amount: 1920000
                      by_client:
                        -
                          client_id: 7
                          client_name: 'Acme Corp'
                          hours: 80.0
                          amount: 1200000
                properties:
                  period:
                    type: object
                    properties:
                      start:
                        type: string
                        example: '2026-01-01'
                      end:
                        type: string
                        example: '2026-12-31'
                  members:
                    type: array
                    example:
                      -
                        user_id: 1
                        name: 'Jane Smith'
                        total_hours: 160
                        billable_hours: 128
                        non_billable_hours: 32
                        utilization_rate: 80
                        billable_amount: 1920000
                        by_client:
                          -
                            client_id: 7
                            client_name: 'Acme Corp'
                            hours: 80
                            amount: 1200000
                    items:
                      type: object
                      properties:
                        user_id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: 'Jane Smith'
                        total_hours:
                          type: number
                          example: 160.0
                        billable_hours:
                          type: number
                          example: 128.0
                        non_billable_hours:
                          type: number
                          example: 32.0
                        utilization_rate:
                          type: number
                          example: 80.0
                        billable_amount:
                          type: integer
                          example: 1920000
                        by_client:
                          type: array
                          example:
                            -
                              client_id: 7
                              client_name: 'Acme Corp'
                              hours: 80
                              amount: 1200000
                          items:
                            type: object
                            properties:
                              client_id:
                                type: integer
                                example: 7
                              client_name:
                                type: string
                                example: 'Acme Corp'
                              hours:
                                type: number
                                example: 80.0
                              amount:
                                type: integer
                                example: 1200000
      tags:
        - Reports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:23'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
  /api/reports/expenses:
    get:
      summary: 'Expense report.'
      operationId: expenseReport
      description: "Returns total expenses with breakdowns by category and by client (billable only) for the\ngiven date range. All amounts in cents."
      parameters:
        -
          in: query
          name: from
          description: 'Start date in YYYY-MM-DD format.'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Start date in YYYY-MM-DD format.'
            example: '2026-01-01'
        -
          in: query
          name: to
          description: 'End date in YYYY-MM-DD format.'
          example: '2026-12-31'
          required: false
          schema:
            type: string
            description: 'End date in YYYY-MM-DD format.'
            example: '2026-12-31'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    total: 85000
                    total_tax: 12750
                    billable_total: 60000
                    by_category:
                      -
                        category: travel
                        total: 30000
                        count: 3
                    by_client:
                      -
                        client: 'Acme Corp'
                        client_id: 7
                        total: 60000
                        count: 5
                properties:
                  data:
                    type: object
                    properties:
                      total:
                        type: integer
                        example: 85000
                      total_tax:
                        type: integer
                        example: 12750
                      billable_total:
                        type: integer
                        example: 60000
                      by_category:
                        type: array
                        example:
                          -
                            category: travel
                            total: 30000
                            count: 3
                        items:
                          type: object
                          properties:
                            category:
                              type: string
                              example: travel
                            total:
                              type: integer
                              example: 30000
                            count:
                              type: integer
                              example: 3
                      by_client:
                        type: array
                        example:
                          -
                            client: 'Acme Corp'
                            client_id: 7
                            total: 60000
                            count: 5
                        items:
                          type: object
                          properties:
                            client:
                              type: string
                              example: 'Acme Corp'
                            client_id:
                              type: integer
                              example: 7
                            total:
                              type: integer
                              example: 60000
                            count:
                              type: integer
                              example: 5
      tags:
        - Reports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:23'
                to:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>from</code>.'
                  example: '2052-04-28'
  /api/reports/invoice-summary:
    get:
      summary: 'Invoice summary report.'
      operationId: invoiceSummaryReport
      description: "Returns invoice counts and totals grouped by currency, status, and client for the given date\nrange. All amounts in cents."
      parameters:
        -
          in: query
          name: start_date
          description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
          example: '2026-01-01'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to start of current year.'
            example: '2026-01-01'
        -
          in: query
          name: end_date
          description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
          example: '2026-12-31'
          required: false
          schema:
            type: string
            description: 'Date in YYYY-MM-DD format. Defaults to end of current year.'
            example: '2026-12-31'
        -
          in: query
          name: client_id
          description: 'Filter to a specific client.'
          example: 7
          required: false
          schema:
            type: integer
            description: 'Filter to a specific client.'
            example: 7
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  totals_by_currency:
                    USD:
                      total_invoiced: 600000
                      total_paid: 480000
                      total_outstanding: 95000
                      total_overdue: 25000
                      invoice_count: 24
                  by_status:
                    paid:
                      count: 18
                      total: 480000
                    sent:
                      count: 4
                      total: 95000
                    overdue:
                      count: 2
                      total: 25000
                  by_client:
                    -
                      client_id: 7
                      client_name: 'Acme Corp'
                      currency: USD
                      invoiced: 300000
                      paid: 240000
                      outstanding: 60000
                properties:
                  totals_by_currency:
                    type: object
                    properties:
                      USD:
                        type: object
                        properties:
                          total_invoiced:
                            type: integer
                            example: 600000
                          total_paid:
                            type: integer
                            example: 480000
                          total_outstanding:
                            type: integer
                            example: 95000
                          total_overdue:
                            type: integer
                            example: 25000
                          invoice_count:
                            type: integer
                            example: 24
                  by_status:
                    type: object
                    properties:
                      paid:
                        type: object
                        properties:
                          count:
                            type: integer
                            example: 18
                          total:
                            type: integer
                            example: 480000
                      sent:
                        type: object
                        properties:
                          count:
                            type: integer
                            example: 4
                          total:
                            type: integer
                            example: 95000
                      overdue:
                        type: object
                        properties:
                          count:
                            type: integer
                            example: 2
                          total:
                            type: integer
                            example: 25000
                  by_client:
                    type: array
                    example:
                      -
                        client_id: 7
                        client_name: 'Acme Corp'
                        currency: USD
                        invoiced: 300000
                        paid: 240000
                        outstanding: 60000
                    items:
                      type: object
                      properties:
                        client_id:
                          type: integer
                          example: 7
                        client_name:
                          type: string
                          example: 'Acme Corp'
                        currency:
                          type: string
                          example: USD
                        invoiced:
                          type: integer
                          example: 300000
                        paid:
                          type: integer
                          example: 240000
                        outstanding:
                          type: integer
                          example: 60000
      tags:
        - Reports
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                start_date:
                  type: string
                  description: 'Must be a valid date.'
                  example: '2026-04-05T19:38:23'
                end_date:
                  type: string
                  description: 'Must be a valid date. Must be a date after or equal to <code>start_date</code>.'
                  example: '2052-04-28'
                client_id:
                  type: integer
                  description: ''
                  example: 16
  /api/activity-log:
    get:
      summary: 'List activity log entries'
      operationId: listActivityLogEntries
      description: ''
      parameters:
        -
          in: query
          name: subject_type
          description: 'The subject type (invoice, quote, credit, recurring-invoice).'
          example: invoice
          required: true
          schema:
            type: string
            description: 'The subject type (invoice, quote, credit, recurring-invoice).'
            example: invoice
        -
          in: query
          name: subject_id
          description: 'The subject ID.'
          example: 1
          required: true
          schema:
            type: integer
            description: 'The subject ID.'
            example: 1
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      description: created
                      event: created
                      causer_name: John
                      properties: {  }
                      created_at: '2026-04-05T00:00:00+00:00'
                  meta:
                    current_page: 1
                    last_page: 1
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        description: created
                        event: created
                        causer_name: John
                        properties: []
                        created_at: '2026-04-05T00:00:00+00:00'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        description:
                          type: string
                          example: created
                        event:
                          type: string
                          example: created
                        causer_name:
                          type: string
                          example: John
                        properties:
                          type: object
                          properties: {  }
                        created_at:
                          type: string
                          example: '2026-04-05T00:00:00+00:00'
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      last_page:
                        type: integer
                        example: 1
                      total:
                        type: integer
                        example: 1
        422:
          description: 'Invalid subject type'
          content:
            text/plain:
              schema:
                type: string
                example: ''
      tags:
        - 'Activity Log'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                subject_type:
                  type: string
                  description: ''
                  example: architecto
                subject_id:
                  type: integer
                  description: ''
                  example: 16
              required:
                - subject_type
                - subject_id
