openapi: 3.0.3
info:
  title: 'Gäld API Documentation'
  description: 'REST API for the Gäld Swiss accounting platform. Manage invoices, contacts, banking, expenses, and accounting data.'
  version: 1.0.0
servers:
  -
    url: 'http://localhost:8080'
tags:
  -
    name: Accounts
    description: "\nRead-only access to the chart of accounts."
  -
    name: Authentication
    description: "\nManage personal API tokens. Tokens are scoped to the authenticated user and current organisation."
  -
    name: 'Bank Accounts'
    description: "\nRead-only access to bank accounts and their balances."
  -
    name: Customers
    description: "\nCRUD operations on customers. Customers are linked to invoices and contact persons."
  -
    name: Expenses
    description: "\nCRUD operations on expenses. Expenses track outgoing payments and costs."
  -
    name: Invoices
    description: "\nCRUD operations on invoices. Invoices support line items, VAT rates, and payment tracking."
  -
    name: Webhooks
    description: "\nCRUD operations on webhook endpoints. Webhooks notify external URLs when events occur."
components:
  securitySchemes:
    default:
      type: http
      scheme: bearer
      description: 'You can retrieve your token by visiting your dashboard and clicking <b>Generate API token</b>.'
security:
  -
    default: []
paths:
  /api/v1/accounts:
    get:
      summary: 'List accounts'
      operationId: listAccounts
      description: 'Returns a paginated list of accounts from the chart of accounts.'
      parameters:
        -
          in: query
          name: type
          description: 'Filter by account type (asset, liability, equity, revenue, expense).'
          example: asset
          required: false
          schema:
            type: string
            description: 'Filter by account type (asset, liability, equity, revenue, expense).'
            example: asset
        -
          in: query
          name: active_only
          description: 'Only return active accounts.'
          example: true
          required: false
          schema:
            type: boolean
            description: 'Only return active accounts.'
            example: true
        -
          in: query
          name: per_page
          description: 'Number of results per page (max 100).'
          example: 50
          required: false
          schema:
            type: integer
            description: 'Number of results per page (max 100).'
            example: 50
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      code: '1000'
                      name: Cash
                      type: asset
                      parent_id: null
                      is_active: true
                      description: 'Liquid funds'
                  links: {  }
                  meta:
                    current_page: 1
                    per_page: 50
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        code: '1000'
                        name: Cash
                        type: asset
                        parent_id: null
                        is_active: true
                        description: 'Liquid funds'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        code:
                          type: string
                          example: '1000'
                        name:
                          type: string
                          example: Cash
                        type:
                          type: string
                          example: asset
                        parent_id:
                          type: string
                          example: null
                          nullable: true
                        is_active:
                          type: boolean
                          example: true
                        description:
                          type: string
                          example: 'Liquid funds'
                  links:
                    type: object
                    properties: {  }
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 50
                      total:
                        type: integer
                        example: 1
      tags:
        - Accounts
  '/api/v1/accounts/{id}':
    get:
      summary: 'Show an account'
      operationId: showAnAccount
      description: 'Returns a single account by UUID.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    code: '1000'
                    name: Cash
                    type: asset
                    parent_id: null
                    is_active: true
                    description: 'Liquid funds'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      code:
                        type: string
                        example: '1000'
                      name:
                        type: string
                        example: Cash
                      type:
                        type: string
                        example: asset
                      parent_id:
                        type: string
                        example: null
                        nullable: true
                      is_active:
                        type: boolean
                        example: true
                      description:
                        type: string
                        example: 'Liquid funds'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Account not found.'
                properties:
                  message:
                    type: string
                    example: 'Account not found.'
      tags:
        - Accounts
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the account.'
        example: 16
        required: true
        schema:
          type: integer
      -
        in: path
        name: account
        description: 'The account UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
  /api/v1/tokens:
    get:
      summary: 'List personal tokens'
      operationId: listPersonalTokens
      description: 'Returns all personal API tokens for the authenticated user in the current organisation.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      name: 'CI Token'
                      abilities:
                        - 'invoices:read'
                      last_used_at: '2025-03-01T12:00:00.000000Z'
                      expires_at: '2025-12-31T23:59:59.000000Z'
                      created_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        name: 'CI Token'
                        abilities:
                          - 'invoices:read'
                        last_used_at: '2025-03-01T12:00:00.000000Z'
                        expires_at: '2025-12-31T23:59:59.000000Z'
                        created_at: '2025-01-15T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: 'CI Token'
                        abilities:
                          type: array
                          example:
                            - 'invoices:read'
                          items:
                            type: string
                        last_used_at:
                          type: string
                          example: '2025-03-01T12:00:00.000000Z'
                        expires_at:
                          type: string
                          example: '2025-12-31T23:59:59.000000Z'
                        created_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
      tags:
        - Authentication
    post:
      summary: 'Create a personal token'
      operationId: createAPersonalToken
      description: 'Creates a new personal API token. The plain-text token is returned only once in the response.'
      parameters: []
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                example:
                  token: 1|abc123def456...
                  name: 'CI Token'
                  type: personal
                  abilities:
                    - 'invoices:read'
                    - 'customers:read'
                  expires_at: '2025-04-15T10:00:00.000000Z'
                properties:
                  token:
                    type: string
                    example: 1|abc123def456...
                  name:
                    type: string
                    example: 'CI Token'
                  type:
                    type: string
                    example: personal
                  abilities:
                    type: array
                    example:
                      - 'invoices:read'
                      - 'customers:read'
                    items:
                      type: string
                  expires_at:
                    type: string
                    example: '2025-04-15T10:00:00.000000Z'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'The name field is required.'
                  errors:
                    name:
                      - 'The name field is required.'
                properties:
                  message:
                    type: string
                    example: 'The name field is required.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        example:
                          - 'The name field is required.'
                        items:
                          type: string
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'A descriptive name for the token.'
                  example: 'CI Token'
                abilities:
                  type: array
                  description: 'List of token abilities (permissions). Use `*` for all.'
                  example:
                    - 'invoices:read'
                    - 'customers:read'
                  items:
                    type: string
                expires_in_days:
                  type: integer
                  description: 'Number of days until the token expires (1-365).'
                  example: 90
                  nullable: true
              required:
                - name
  '/api/v1/tokens/{id}':
    delete:
      summary: 'Revoke a personal token'
      operationId: revokeAPersonalToken
      description: 'Permanently deletes a personal API token.'
      parameters: []
      responses:
        204:
          description: Revoked
          content:
            text/plain:
              schema:
                type: string
                example: ''
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Token not found.'
                properties:
                  message:
                    type: string
                    example: 'Token not found.'
      tags:
        - Authentication
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the token.'
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: tokenId
        description: 'The token ID.'
        example: 1
        required: true
        schema:
          type: integer
  /api/v1/org-tokens:
    get:
      summary: 'List organisation tokens'
      operationId: listOrganisationTokens
      description: 'Returns all organisation-scoped API tokens for the current organisation.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 1
                      name: 'Production Key'
                      abilities:
                        - '*'
                      last_used_at: '2025-03-15T08:00:00.000000Z'
                      expires_at: null
                      created_at: '2025-01-10T10:00:00.000000Z'
                      created_by: 'John Doe'
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 1
                        name: 'Production Key'
                        abilities:
                          - '*'
                        last_used_at: '2025-03-15T08:00:00.000000Z'
                        expires_at: null
                        created_at: '2025-01-10T10:00:00.000000Z'
                        created_by: 'John Doe'
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: 'Production Key'
                        abilities:
                          type: array
                          example:
                            - '*'
                          items:
                            type: string
                        last_used_at:
                          type: string
                          example: '2025-03-15T08:00:00.000000Z'
                        expires_at:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2025-01-10T10:00:00.000000Z'
                        created_by:
                          type: string
                          example: 'John Doe'
      tags:
        - Authentication
    post:
      summary: 'Create an organisation token'
      operationId: createAnOrganisationToken
      description: 'Creates a new organisation-scoped API token. The plain-text token is returned only once.'
      parameters: []
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                example:
                  token: 2|xyz789...
                  name: 'Production Key'
                  type: organization
                  abilities:
                    - '*'
                  expires_at: null
                properties:
                  token:
                    type: string
                    example: 2|xyz789...
                  name:
                    type: string
                    example: 'Production Key'
                  type:
                    type: string
                    example: organization
                  abilities:
                    type: array
                    example:
                      - '*'
                    items:
                      type: string
                  expires_at:
                    type: string
                    example: null
                    nullable: true
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This action is unauthorized.'
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'The name field is required.'
                  errors:
                    name:
                      - 'The name field is required.'
                properties:
                  message:
                    type: string
                    example: 'The name field is required.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        example:
                          - 'The name field is required.'
                        items:
                          type: string
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'A descriptive name for the token.'
                  example: 'Production Key'
                abilities:
                  type: array
                  description: 'Token abilities. Use `*` for full access.'
                  example:
                    - '*'
                  items:
                    type: string
                expires_in_days:
                  type: integer
                  description: 'Number of days until the token expires (1-365).'
                  example: 365
                  nullable: true
              required:
                - name
  '/api/v1/org-tokens/{token}':
    delete:
      summary: 'Revoke an organisation token'
      operationId: revokeAnOrganisationToken
      description: 'Permanently deletes an organisation-scoped API token.'
      parameters: []
      responses:
        204:
          description: Revoked
          content:
            text/plain:
              schema:
                type: string
                example: ''
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This action is unauthorized.'
                properties:
                  message:
                    type: string
                    example: 'This action is unauthorized.'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Token not found.'
                properties:
                  message:
                    type: string
                    example: 'Token not found.'
      tags:
        - Authentication
    parameters:
      -
        in: path
        name: token
        description: ''
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: tokenId
        description: 'The token ID.'
        example: 1
        required: true
        schema:
          type: integer
  /api/v1/meta/abilities:
    get:
      summary: 'List available abilities'
      operationId: listAvailableAbilities
      description: 'Returns all possible token abilities (permissions) that can be assigned to a token.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    - 'customers:read'
                    - 'customers:write'
                    - 'invoices:read'
                    - 'invoices:write'
                    - 'expenses:read'
                    - 'expenses:write'
                    - 'accounts:read'
                    - 'bank-accounts:read'
                    - 'webhooks:read'
                    - 'webhooks:write'
                properties:
                  data:
                    type: array
                    example:
                      - 'customers:read'
                      - 'customers:write'
                      - 'invoices:read'
                      - 'invoices:write'
                      - 'expenses:read'
                      - 'expenses:write'
                      - 'accounts:read'
                      - 'bank-accounts:read'
                      - 'webhooks:read'
                      - 'webhooks:write'
                    items:
                      type: string
      tags:
        - Authentication
  /api/v1/meta/webhook-events:
    get:
      summary: 'List webhook events'
      operationId: listWebhookEvents
      description: 'Returns all possible webhook event types that can be subscribed to.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    - invoice.created
                    - invoice.updated
                    - invoice.deleted
                    - invoice.paid
                    - customer.created
                    - customer.updated
                    - customer.deleted
                    - expense.created
                    - expense.updated
                    - expense.deleted
                    - payment.received
                    - payment.deleted
                properties:
                  data:
                    type: array
                    example:
                      - invoice.created
                      - invoice.updated
                      - invoice.deleted
                      - invoice.paid
                      - customer.created
                      - customer.updated
                      - customer.deleted
                      - expense.created
                      - expense.updated
                      - expense.deleted
                      - payment.received
                      - payment.deleted
                    items:
                      type: string
      tags:
        - Authentication
  /api/v1/bank-accounts:
    get:
      summary: 'List bank accounts'
      operationId: listBankAccounts
      description: 'Returns a paginated list of bank accounts.'
      parameters:
        -
          in: query
          name: active_only
          description: 'Only return active bank accounts.'
          example: true
          required: false
          schema:
            type: boolean
            description: 'Only return active bank accounts.'
            example: true
        -
          in: query
          name: per_page
          description: 'Number of results per page (max 100).'
          example: 25
          required: false
          schema:
            type: integer
            description: 'Number of results per page (max 100).'
            example: 25
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      name: 'UBS Business'
                      iban: 'CH93 0076 2011 6238 5295 7'
                      bank_name: UBS
                      currency: CHF
                      balance: 12500.0
                      is_active: true
                      account_id: abc123
                      created_at: '2025-01-01T00:00:00.000000Z'
                      updated_at: '2025-01-15T10:00:00.000000Z'
                  links: {  }
                  meta:
                    current_page: 1
                    per_page: 25
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        name: 'UBS Business'
                        iban: 'CH93 0076 2011 6238 5295 7'
                        bank_name: UBS
                        currency: CHF
                        balance: 12500
                        is_active: true
                        account_id: abc123
                        created_at: '2025-01-01T00:00:00.000000Z'
                        updated_at: '2025-01-15T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        name:
                          type: string
                          example: 'UBS Business'
                        iban:
                          type: string
                          example: 'CH93 0076 2011 6238 5295 7'
                        bank_name:
                          type: string
                          example: UBS
                        currency:
                          type: string
                          example: CHF
                        balance:
                          type: number
                          example: 12500.0
                        is_active:
                          type: boolean
                          example: true
                        account_id:
                          type: string
                          example: abc123
                        created_at:
                          type: string
                          example: '2025-01-01T00:00:00.000000Z'
                        updated_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                  links:
                    type: object
                    properties: {  }
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 25
                      total:
                        type: integer
                        example: 1
      tags:
        - 'Bank Accounts'
  '/api/v1/bank-accounts/{bankAccount_id}':
    get:
      summary: 'Show a bank account'
      operationId: showABankAccount
      description: 'Returns a single bank account by UUID.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    name: 'UBS Business'
                    iban: 'CH93 0076 2011 6238 5295 7'
                    bank_name: UBS
                    currency: CHF
                    balance: 12500.0
                    is_active: true
                    account_id: abc123
                    created_at: '2025-01-01T00:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      name:
                        type: string
                        example: 'UBS Business'
                      iban:
                        type: string
                        example: 'CH93 0076 2011 6238 5295 7'
                      bank_name:
                        type: string
                        example: UBS
                      currency:
                        type: string
                        example: CHF
                      balance:
                        type: number
                        example: 12500.0
                      is_active:
                        type: boolean
                        example: true
                      account_id:
                        type: string
                        example: abc123
                      created_at:
                        type: string
                        example: '2025-01-01T00:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Bank account not found.'
                properties:
                  message:
                    type: string
                    example: 'Bank account not found.'
      tags:
        - 'Bank Accounts'
    parameters:
      -
        in: path
        name: bankAccount_id
        description: 'The ID of the bankAccount.'
        example: 16
        required: true
        schema:
          type: integer
      -
        in: path
        name: bank_account
        description: 'The bank account UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
  /api/v1/customers:
    get:
      summary: 'List customers'
      operationId: listCustomers
      description: 'Returns a paginated list of customers for the current organisation.'
      parameters:
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
        -
          in: query
          name: search
          description: 'Search by customer name or email.'
          example: ACME
          required: false
          schema:
            type: string
            description: 'Search by customer name or email.'
            example: ACME
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      type: company
                      name: 'ACME GmbH'
                      email: info@acme.ch
                      phone: '+41 44 123 45 67'
                      address: 'Bahnhofstrasse 1'
                      city: Zürich
                      postal_code: '8001'
                      country: CH
                      vat_number: CHE-123.456.789
                      currency: CHF
                      payment_terms: '30 days net'
                      contact_persons: []
                      created_at: '2025-01-15T10:00:00.000000Z'
                      updated_at: '2025-01-15T10:00:00.000000Z'
                  links: {  }
                  meta:
                    current_page: 1
                    per_page: 20
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        type: company
                        name: 'ACME GmbH'
                        email: info@acme.ch
                        phone: '+41 44 123 45 67'
                        address: 'Bahnhofstrasse 1'
                        city: Zürich
                        postal_code: '8001'
                        country: CH
                        vat_number: CHE-123.456.789
                        currency: CHF
                        payment_terms: '30 days net'
                        contact_persons: []
                        created_at: '2025-01-15T10:00:00.000000Z'
                        updated_at: '2025-01-15T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        type:
                          type: string
                          example: company
                        name:
                          type: string
                          example: 'ACME GmbH'
                        email:
                          type: string
                          example: info@acme.ch
                        phone:
                          type: string
                          example: '+41 44 123 45 67'
                        address:
                          type: string
                          example: 'Bahnhofstrasse 1'
                        city:
                          type: string
                          example: Zürich
                        postal_code:
                          type: string
                          example: '8001'
                        country:
                          type: string
                          example: CH
                        vat_number:
                          type: string
                          example: CHE-123.456.789
                        currency:
                          type: string
                          example: CHF
                        payment_terms:
                          type: string
                          example: '30 days net'
                        contact_persons:
                          type: array
                          example: []
                        created_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                        updated_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                  links:
                    type: object
                    properties: {  }
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 20
                      total:
                        type: integer
                        example: 1
      tags:
        - Customers
    post:
      summary: 'Create a customer'
      operationId: createACustomer
      description: 'Creates a new customer in the current organisation.'
      parameters: []
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    type: null
                    name: 'ACME GmbH'
                    email: info@acme.ch
                    phone: '+41 44 123 45 67'
                    address: 'Bahnhofstrasse 1'
                    city: Zürich
                    postal_code: '8001'
                    country: CH
                    vat_number: CHE-123.456.789
                    currency: CHF
                    payment_terms: '30 days net'
                    contact_persons: []
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      type:
                        type: string
                        example: null
                        nullable: true
                      name:
                        type: string
                        example: 'ACME GmbH'
                      email:
                        type: string
                        example: info@acme.ch
                      phone:
                        type: string
                        example: '+41 44 123 45 67'
                      address:
                        type: string
                        example: 'Bahnhofstrasse 1'
                      city:
                        type: string
                        example: Zürich
                      postal_code:
                        type: string
                        example: '8001'
                      country:
                        type: string
                        example: CH
                      vat_number:
                        type: string
                        example: CHE-123.456.789
                      currency:
                        type: string
                        example: CHF
                      payment_terms:
                        type: string
                        example: '30 days net'
                      contact_persons:
                        type: array
                        example: []
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'The name field is required.'
                  errors:
                    name:
                      - 'The name field is required.'
                properties:
                  message:
                    type: string
                    example: 'The name field is required.'
                  errors:
                    type: object
                    properties:
                      name:
                        type: array
                        example:
                          - 'The name field is required.'
                        items:
                          type: string
      tags:
        - Customers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'The customer name.'
                  example: 'ACME GmbH'
                email:
                  type: string
                  description: 'The customer email.'
                  example: info@acme.ch
                  nullable: true
                phone:
                  type: string
                  description: 'Phone number.'
                  example: '+41 44 123 45 67'
                  nullable: true
                address:
                  type: string
                  description: 'Street address.'
                  example: 'Bahnhofstrasse 1'
                  nullable: true
                city:
                  type: string
                  description: City.
                  example: Zürich
                  nullable: true
                postal_code:
                  type: string
                  description: 'Postal code.'
                  example: '8001'
                  nullable: true
                country:
                  type: string
                  description: 'ISO 3166-1 alpha-2 country code.'
                  example: CH
                  nullable: true
                vat_number:
                  type: string
                  description: 'VAT registration number.'
                  example: CHE-123.456.789
                  nullable: true
                currency:
                  type: string
                  description: 'ISO 4217 currency code.'
                  example: CHF
                  nullable: true
                payment_terms:
                  type: string
                  description: 'Default payment terms.'
                  example: '30 days net'
                  nullable: true
                internal_notes:
                  type: string
                  description: 'Internal notes (not shown on invoices).'
                  example: null
                  nullable: true
              required:
                - name
  '/api/v1/customers/{id}':
    get:
      summary: 'Show a customer'
      operationId: showACustomer
      description: 'Returns a single customer by UUID.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    type: company
                    name: 'ACME GmbH'
                    email: info@acme.ch
                    phone: '+41 44 123 45 67'
                    address: 'Bahnhofstrasse 1'
                    city: Zürich
                    postal_code: '8001'
                    country: CH
                    vat_number: CHE-123.456.789
                    currency: CHF
                    payment_terms: '30 days net'
                    contact_persons: []
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      type:
                        type: string
                        example: company
                      name:
                        type: string
                        example: 'ACME GmbH'
                      email:
                        type: string
                        example: info@acme.ch
                      phone:
                        type: string
                        example: '+41 44 123 45 67'
                      address:
                        type: string
                        example: 'Bahnhofstrasse 1'
                      city:
                        type: string
                        example: Zürich
                      postal_code:
                        type: string
                        example: '8001'
                      country:
                        type: string
                        example: CH
                      vat_number:
                        type: string
                        example: CHE-123.456.789
                      currency:
                        type: string
                        example: CHF
                      payment_terms:
                        type: string
                        example: '30 days net'
                      contact_persons:
                        type: array
                        example: []
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Customer not found.'
                properties:
                  message:
                    type: string
                    example: 'Customer not found.'
      tags:
        - Customers
    put:
      summary: 'Update a customer'
      operationId: updateACustomer
      description: 'Updates an existing customer. Only provided fields are changed.'
      parameters: []
      responses:
        200:
          description: Updated
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    type: company
                    name: 'ACME AG'
                    email: billing@acme.ch
                    phone: '+41 44 123 45 67'
                    address: 'Bahnhofstrasse 1'
                    city: Zürich
                    postal_code: '8001'
                    country: CH
                    vat_number: CHE-123.456.789
                    currency: CHF
                    payment_terms: '30 days net'
                    contact_persons: []
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-20T14:30:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      type:
                        type: string
                        example: company
                      name:
                        type: string
                        example: 'ACME AG'
                      email:
                        type: string
                        example: billing@acme.ch
                      phone:
                        type: string
                        example: '+41 44 123 45 67'
                      address:
                        type: string
                        example: 'Bahnhofstrasse 1'
                      city:
                        type: string
                        example: Zürich
                      postal_code:
                        type: string
                        example: '8001'
                      country:
                        type: string
                        example: CH
                      vat_number:
                        type: string
                        example: CHE-123.456.789
                      currency:
                        type: string
                        example: CHF
                      payment_terms:
                        type: string
                        example: '30 days net'
                      contact_persons:
                        type: array
                        example: []
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-20T14:30:00.000000Z'
      tags:
        - Customers
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'The customer name.'
                  example: 'ACME AG'
                email:
                  type: string
                  description: 'The customer email.'
                  example: billing@acme.ch
                  nullable: true
                phone:
                  type: string
                  description: 'Phone number.'
                  example: '+41 44 123 45 67'
                  nullable: true
                address:
                  type: string
                  description: 'Street address.'
                  example: 'Bahnhofstrasse 1'
                  nullable: true
                city:
                  type: string
                  description: City.
                  example: Zürich
                  nullable: true
                postal_code:
                  type: string
                  description: 'Postal code.'
                  example: '8001'
                  nullable: true
                country:
                  type: string
                  description: 'ISO 3166-1 alpha-2 country code.'
                  example: CH
                  nullable: true
                vat_number:
                  type: string
                  description: 'VAT registration number.'
                  example: CHE-123.456.789
                  nullable: true
                currency:
                  type: string
                  description: 'ISO 4217 currency code.'
                  example: CHF
                  nullable: true
                payment_terms:
                  type: string
                  description: 'Default payment terms.'
                  example: '30 days net'
                  nullable: true
                internal_notes:
                  type: string
                  description: 'Internal notes (not shown on invoices).'
                  example: null
                  nullable: true
    delete:
      summary: 'Delete a customer'
      operationId: deleteACustomer
      description: 'Permanently deletes a customer. This will fail if the customer has linked invoices.'
      parameters: []
      responses:
        204:
          description: Deleted
          content:
            text/plain:
              schema:
                type: string
                example: ''
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Customer not found.'
                properties:
                  message:
                    type: string
                    example: 'Customer not found.'
      tags:
        - Customers
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the customer.'
        example: 16
        required: true
        schema:
          type: integer
      -
        in: path
        name: customer
        description: 'The customer UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
  /api/v1/expenses:
    get:
      summary: 'List expenses'
      operationId: listExpenses
      description: 'Returns a paginated list of expenses for the current organisation.'
      parameters:
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
        -
          in: query
          name: search
          description: 'Search by vendor, category or description.'
          example: Office
          required: false
          schema:
            type: string
            description: 'Search by vendor, category or description.'
            example: Office
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      category: 'Office supplies'
                      description: 'Printer paper'
                      amount: 45.9
                      vat_amount: 3.45
                      date: '2025-02-10'
                      vendor: Digitec
                      status: pending
                      currency: CHF
                      supplier_id: null
                      created_at: '2025-02-10T08:00:00.000000Z'
                      updated_at: '2025-02-10T08:00:00.000000Z'
                  links: {  }
                  meta:
                    current_page: 1
                    per_page: 20
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        category: 'Office supplies'
                        description: 'Printer paper'
                        amount: 45.9
                        vat_amount: 3.45
                        date: '2025-02-10'
                        vendor: Digitec
                        status: pending
                        currency: CHF
                        supplier_id: null
                        created_at: '2025-02-10T08:00:00.000000Z'
                        updated_at: '2025-02-10T08:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        category:
                          type: string
                          example: 'Office supplies'
                        description:
                          type: string
                          example: 'Printer paper'
                        amount:
                          type: number
                          example: 45.9
                        vat_amount:
                          type: number
                          example: 3.45
                        date:
                          type: string
                          example: '2025-02-10'
                        vendor:
                          type: string
                          example: Digitec
                        status:
                          type: string
                          example: pending
                        currency:
                          type: string
                          example: CHF
                        supplier_id:
                          type: string
                          example: null
                          nullable: true
                        created_at:
                          type: string
                          example: '2025-02-10T08:00:00.000000Z'
                        updated_at:
                          type: string
                          example: '2025-02-10T08:00:00.000000Z'
                  links:
                    type: object
                    properties: {  }
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 20
                      total:
                        type: integer
                        example: 1
      tags:
        - Expenses
  '/api/v1/expenses/{id}':
    get:
      summary: 'Show an expense'
      operationId: showAnExpense
      description: 'Returns a single expense by UUID.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    category: 'Office supplies'
                    description: 'Printer paper'
                    amount: 45.9
                    vat_amount: 3.45
                    date: '2025-02-10'
                    vendor: Digitec
                    status: pending
                    currency: CHF
                    supplier_id: null
                    created_at: '2025-02-10T08:00:00.000000Z'
                    updated_at: '2025-02-10T08:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      category:
                        type: string
                        example: 'Office supplies'
                      description:
                        type: string
                        example: 'Printer paper'
                      amount:
                        type: number
                        example: 45.9
                      vat_amount:
                        type: number
                        example: 3.45
                      date:
                        type: string
                        example: '2025-02-10'
                      vendor:
                        type: string
                        example: Digitec
                      status:
                        type: string
                        example: pending
                      currency:
                        type: string
                        example: CHF
                      supplier_id:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2025-02-10T08:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-02-10T08:00:00.000000Z'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Expense not found.'
                properties:
                  message:
                    type: string
                    example: 'Expense not found.'
      tags:
        - Expenses
    delete:
      summary: 'Delete an expense'
      operationId: deleteAnExpense
      description: 'Permanently deletes an expense.'
      parameters: []
      responses:
        204:
          description: Deleted
          content:
            text/plain:
              schema:
                type: string
                example: ''
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Expense not found.'
                properties:
                  message:
                    type: string
                    example: 'Expense not found.'
      tags:
        - Expenses
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the expense.'
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: expense
        description: 'The expense UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
  /api/v1/invoices:
    get:
      summary: 'List invoices'
      operationId: listInvoices
      description: 'Returns a paginated list of invoices for the current organisation.'
      parameters:
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
        -
          in: query
          name: sort
          description: 'Sort field. Allowed: `issue_date`, `due_date`, `total`, `number`, `status`. Prefix with `-` for descending.'
          example: '-issue_date'
          required: false
          schema:
            type: string
            description: 'Sort field. Allowed: `issue_date`, `due_date`, `total`, `number`, `status`. Prefix with `-` for descending.'
            example: '-issue_date'
        -
          in: query
          name: 'filter[status]'
          description: 'Filter by status (e.g. `draft`, `sent`, `paid`).'
          example: sent
          required: false
          schema:
            type: string
            description: 'Filter by status (e.g. `draft`, `sent`, `paid`).'
            example: sent
        -
          in: query
          name: 'filter[type]'
          description: 'Filter by type (e.g. `invoice`, `credit_note`).'
          example: invoice
          required: false
          schema:
            type: string
            description: 'Filter by type (e.g. `invoice`, `credit_note`).'
            example: invoice
        -
          in: query
          name: search
          description: 'Search by invoice number or customer name.'
          example: INV-2025
          required: false
          schema:
            type: string
            description: 'Search by invoice number or customer name.'
            example: INV-2025
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      number: INV-2025-001
                      status: sent
                      type: invoice
                      related_invoice_id: null
                      customer:
                        id: 9c8f...
                        type: company
                        name: 'ACME GmbH'
                      issue_date: '2025-01-15'
                      due_date: '2025-02-14'
                      subtotal: '1000.00'
                      vat_amount: '81.00'
                      total: '1081.00'
                      currency: CHF
                      notes: null
                      payment_terms: '30 days net'
                      amount_paid: '0.00'
                      amount_due: '1081.00'
                      lines: []
                      payments: []
                      created_at: '2025-01-15T10:00:00.000000Z'
                      updated_at: '2025-01-15T10:00:00.000000Z'
                  links:
                    first: ...
                    last: ...
                    prev: null
                    next: ...
                  meta:
                    current_page: 1
                    from: 1
                    last_page: 1
                    per_page: 20
                    to: 1
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        number: INV-2025-001
                        status: sent
                        type: invoice
                        related_invoice_id: null
                        customer:
                          id: 9c8f...
                          type: company
                          name: 'ACME GmbH'
                        issue_date: '2025-01-15'
                        due_date: '2025-02-14'
                        subtotal: '1000.00'
                        vat_amount: '81.00'
                        total: '1081.00'
                        currency: CHF
                        notes: null
                        payment_terms: '30 days net'
                        amount_paid: '0.00'
                        amount_due: '1081.00'
                        lines: []
                        payments: []
                        created_at: '2025-01-15T10:00:00.000000Z'
                        updated_at: '2025-01-15T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        number:
                          type: string
                          example: INV-2025-001
                        status:
                          type: string
                          example: sent
                        type:
                          type: string
                          example: invoice
                        related_invoice_id:
                          type: string
                          example: null
                          nullable: true
                        customer:
                          type: object
                          properties:
                            id:
                              type: string
                              example: 9c8f...
                            type:
                              type: string
                              example: company
                            name:
                              type: string
                              example: 'ACME GmbH'
                        issue_date:
                          type: string
                          example: '2025-01-15'
                        due_date:
                          type: string
                          example: '2025-02-14'
                        subtotal:
                          type: string
                          example: '1000.00'
                        vat_amount:
                          type: string
                          example: '81.00'
                        total:
                          type: string
                          example: '1081.00'
                        currency:
                          type: string
                          example: CHF
                        notes:
                          type: string
                          example: null
                          nullable: true
                        payment_terms:
                          type: string
                          example: '30 days net'
                        amount_paid:
                          type: string
                          example: '0.00'
                        amount_due:
                          type: string
                          example: '1081.00'
                        lines:
                          type: array
                          example: []
                        payments:
                          type: array
                          example: []
                        created_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                        updated_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                  links:
                    type: object
                    properties:
                      first:
                        type: string
                        example: ...
                      last:
                        type: string
                        example: ...
                      prev:
                        type: string
                        example: null
                        nullable: true
                      next:
                        type: string
                        example: ...
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      from:
                        type: integer
                        example: 1
                      last_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 20
                      to:
                        type: integer
                        example: 1
                      total:
                        type: integer
                        example: 1
      tags:
        - Invoices
  '/api/v1/invoices/{id}':
    get:
      summary: 'Show invoice'
      operationId: showInvoice
      description: 'Returns a single invoice with its customer, line items, and payments.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f...
                    number: INV-2025-001
                    status: sent
                    type: invoice
                    related_invoice_id: null
                    customer:
                      id: 9c8f...
                      type: company
                      name: 'ACME GmbH'
                      email: info@acme.ch
                    issue_date: '2025-01-15'
                    due_date: '2025-02-14'
                    subtotal: '1000.00'
                    vat_amount: '81.00'
                    total: '1081.00'
                    currency: CHF
                    notes: null
                    payment_terms: '30 days net'
                    amount_paid: '0.00'
                    amount_due: '1081.00'
                    lines:
                      -
                        id: uuid
                        description: Consulting
                        quantity: '10.00'
                        unit_price: '100.00'
                        amount: '1000.00'
                        vat_rate_id: uuid
                        vat_amount: '81.00'
                        sort_order: 1
                    payments: []
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f...
                      number:
                        type: string
                        example: INV-2025-001
                      status:
                        type: string
                        example: sent
                      type:
                        type: string
                        example: invoice
                      related_invoice_id:
                        type: string
                        example: null
                        nullable: true
                      customer:
                        type: object
                        properties:
                          id:
                            type: string
                            example: 9c8f...
                          type:
                            type: string
                            example: company
                          name:
                            type: string
                            example: 'ACME GmbH'
                          email:
                            type: string
                            example: info@acme.ch
                      issue_date:
                        type: string
                        example: '2025-01-15'
                      due_date:
                        type: string
                        example: '2025-02-14'
                      subtotal:
                        type: string
                        example: '1000.00'
                      vat_amount:
                        type: string
                        example: '81.00'
                      total:
                        type: string
                        example: '1081.00'
                      currency:
                        type: string
                        example: CHF
                      notes:
                        type: string
                        example: null
                        nullable: true
                      payment_terms:
                        type: string
                        example: '30 days net'
                      amount_paid:
                        type: string
                        example: '0.00'
                      amount_due:
                        type: string
                        example: '1081.00'
                      lines:
                        type: array
                        example:
                          -
                            id: uuid
                            description: Consulting
                            quantity: '10.00'
                            unit_price: '100.00'
                            amount: '1000.00'
                            vat_rate_id: uuid
                            vat_amount: '81.00'
                            sort_order: 1
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              example: uuid
                            description:
                              type: string
                              example: Consulting
                            quantity:
                              type: string
                              example: '10.00'
                            unit_price:
                              type: string
                              example: '100.00'
                            amount:
                              type: string
                              example: '1000.00'
                            vat_rate_id:
                              type: string
                              example: uuid
                            vat_amount:
                              type: string
                              example: '81.00'
                            sort_order:
                              type: integer
                              example: 1
                      payments:
                        type: array
                        example: []
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'No query results for model [Invoice].'
                properties:
                  message:
                    type: string
                    example: 'No query results for model [Invoice].'
      tags:
        - Invoices
    delete:
      summary: 'Delete invoice'
      operationId: deleteInvoice
      description: 'Permanently deletes an invoice. Only draft invoices can be deleted.'
      parameters: []
      responses:
        204:
          description: Deleted
          content:
            text/plain:
              schema:
                type: string
                example: ''
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'No query results for model [Invoice].'
                properties:
                  message:
                    type: string
                    example: 'No query results for model [Invoice].'
      tags:
        - Invoices
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the invoice.'
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: invoice
        description: 'The UUID of the invoice.'
        example: 9c8f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b
        required: true
        schema:
          type: string
  /api/v1/webhooks:
    get:
      summary: 'List webhooks'
      operationId: listWebhooks
      description: 'Returns a paginated list of webhook endpoints for the current organisation.'
      parameters:
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    -
                      id: 9c8f...
                      url: 'https://example.com/webhook'
                      events:
                        - invoice.created
                        - invoice.paid
                      is_active: true
                      last_triggered_at: '2025-03-01T12:00:00.000000Z'
                      created_at: '2025-01-15T10:00:00.000000Z'
                      updated_at: '2025-01-15T10:00:00.000000Z'
                  links: {  }
                  meta:
                    current_page: 1
                    per_page: 15
                    total: 1
                properties:
                  data:
                    type: array
                    example:
                      -
                        id: 9c8f...
                        url: 'https://example.com/webhook'
                        events:
                          - invoice.created
                          - invoice.paid
                        is_active: true
                        last_triggered_at: '2025-03-01T12:00:00.000000Z'
                        created_at: '2025-01-15T10:00:00.000000Z'
                        updated_at: '2025-01-15T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9c8f...
                        url:
                          type: string
                          example: 'https://example.com/webhook'
                        events:
                          type: array
                          example:
                            - invoice.created
                            - invoice.paid
                          items:
                            type: string
                        is_active:
                          type: boolean
                          example: true
                        last_triggered_at:
                          type: string
                          example: '2025-03-01T12:00:00.000000Z'
                        created_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                        updated_at:
                          type: string
                          example: '2025-01-15T10:00:00.000000Z'
                  links:
                    type: object
                    properties: {  }
                  meta:
                    type: object
                    properties:
                      current_page:
                        type: integer
                        example: 1
                      per_page:
                        type: integer
                        example: 15
                      total:
                        type: integer
                        example: 1
      tags:
        - Webhooks
    post:
      summary: 'Create a webhook'
      operationId: createAWebhook
      description: "Creates a new webhook endpoint. The webhook secret is returned only in the response\nof this endpoint — store it securely."
      parameters: []
      responses:
        201:
          description: Created
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    url: 'https://example.com/webhook'
                    events:
                      - invoice.created
                      - invoice.paid
                    is_active: true
                    last_triggered_at: null
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                  secret: whsec_abc123...
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      url:
                        type: string
                        example: 'https://example.com/webhook'
                      events:
                        type: array
                        example:
                          - invoice.created
                          - invoice.paid
                        items:
                          type: string
                      is_active:
                        type: boolean
                        example: true
                      last_triggered_at:
                        type: string
                        example: null
                        nullable: true
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                  secret:
                    type: string
                    example: whsec_abc123...
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'The url field is required.'
                  errors:
                    url:
                      - 'The url field is required.'
                properties:
                  message:
                    type: string
                    example: 'The url field is required.'
                  errors:
                    type: object
                    properties:
                      url:
                        type: array
                        example:
                          - 'The url field is required.'
                        items:
                          type: string
      tags:
        - Webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: 'The endpoint URL (must be HTTPS).'
                  example: 'https://example.com/webhook'
                events:
                  type: array
                  description: 'Events to subscribe to.'
                  example:
                    - invoice.created
                    - invoice.paid
                  items:
                    type: string
                is_active:
                  type: boolean
                  description: 'Whether the webhook is active. Default: true.'
                  example: true
              required:
                - url
                - events
  '/api/v1/webhooks/{id}':
    get:
      summary: 'Show a webhook'
      operationId: showAWebhook
      description: 'Returns a single webhook endpoint by UUID.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    url: 'https://example.com/webhook'
                    events:
                      - invoice.created
                      - invoice.paid
                    is_active: true
                    last_triggered_at: '2025-03-01T12:00:00.000000Z'
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-01-15T10:00:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      url:
                        type: string
                        example: 'https://example.com/webhook'
                      events:
                        type: array
                        example:
                          - invoice.created
                          - invoice.paid
                        items:
                          type: string
                      is_active:
                        type: boolean
                        example: true
                      last_triggered_at:
                        type: string
                        example: '2025-03-01T12:00:00.000000Z'
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Webhook not found.'
                properties:
                  message:
                    type: string
                    example: 'Webhook not found.'
      tags:
        - Webhooks
    put:
      summary: 'Update a webhook'
      operationId: updateAWebhook
      description: 'Updates an existing webhook endpoint. Only provided fields are changed.'
      parameters: []
      responses:
        200:
          description: Updated
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                    url: 'https://example.com/webhook-v2'
                    events:
                      - invoice.created
                      - customer.created
                    is_active: false
                    last_triggered_at: '2025-03-01T12:00:00.000000Z'
                    created_at: '2025-01-15T10:00:00.000000Z'
                    updated_at: '2025-03-20T14:30:00.000000Z'
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
                      url:
                        type: string
                        example: 'https://example.com/webhook-v2'
                      events:
                        type: array
                        example:
                          - invoice.created
                          - customer.created
                        items:
                          type: string
                      is_active:
                        type: boolean
                        example: false
                      last_triggered_at:
                        type: string
                        example: '2025-03-01T12:00:00.000000Z'
                      created_at:
                        type: string
                        example: '2025-01-15T10:00:00.000000Z'
                      updated_at:
                        type: string
                        example: '2025-03-20T14:30:00.000000Z'
      tags:
        - Webhooks
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: 'The endpoint URL (must be HTTPS).'
                  example: 'https://example.com/webhook-v2'
                events:
                  type: array
                  description: 'Events to subscribe to.'
                  example:
                    - invoice.created
                    - customer.created
                  items:
                    type: string
                is_active:
                  type: boolean
                  description: 'Whether the webhook is active.'
                  example: false
    delete:
      summary: 'Delete a webhook'
      operationId: deleteAWebhook
      description: 'Permanently deletes a webhook endpoint.'
      parameters: []
      responses:
        204:
          description: Deleted
          content:
            text/plain:
              schema:
                type: string
                example: ''
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Webhook not found.'
                properties:
                  message:
                    type: string
                    example: 'Webhook not found.'
      tags:
        - Webhooks
    parameters:
      -
        in: path
        name: id
        description: 'The ID of the webhook.'
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: webhook
        description: 'The webhook UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
  '/api/v1/webhooks/{webhook_id}/regenerate-secret':
    post:
      summary: 'Regenerate webhook secret'
      operationId: regenerateWebhookSecret
      description: 'Generates a new signing secret for the webhook. The old secret is immediately invalidated.'
      parameters: []
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: object
                example:
                  secret: whsec_new789...
                  message: 'Webhook secret regenerated.'
                properties:
                  secret:
                    type: string
                    example: whsec_new789...
                  message:
                    type: string
                    example: 'Webhook secret regenerated.'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Webhook not found.'
                properties:
                  message:
                    type: string
                    example: 'Webhook not found.'
      tags:
        - Webhooks
    parameters:
      -
        in: path
        name: webhook_id
        description: 'The ID of the webhook.'
        example: architecto
        required: true
        schema:
          type: string
      -
        in: path
        name: webhook
        description: 'The webhook UUID.'
        example: 9c8f1b2a-3d4e-5f67-8901-abcdef123456
        required: true
        schema:
          type: string
