openapi: 3.1.0
info:
  title: Saturation API
  version: 1.0.0
  description: >-
    Read and write production finance data in Saturation. Authenticate with a
    personal token in the `Authorization` header: `Bearer <token>`. Create a
    token under Settings > Developers > API. Each token belongs to one
    workspace.

    Conventions:

    - Successful responses contain the requested resource. Lists contain `data`
    and an optional `nextCursor`. Errors contain `success`, `code`, `message`,
    and `requestId`.

    - Money uses integer minor units and an ISO-4217 currency, for example `{
    "amount": 152900, "currency": "USD" }`. Dates use ISO 8601.

    - Lists default to 50 items and allow up to 100. Pass `nextCursor` as
    `cursor` for the next page. Set `withCount=true` to include the total count.

    - `404 not_found` means the resource does not exist or is not available to
    the token.
  contact:
    name: Saturation API
    url: https://docs.saturation.io
  license:
    name: Proprietary
    url: https://saturation.io/terms
servers:
  - url: https://next-api.saturation.io/v1
    description: Configured environment
security:
  - bearerAuth: []
tags:
  - name: Meta
    description: Identity and workspace for the current token.
  - name: Projects
    description: Create and manage projects.
  - name: Spaces
    description: Folders that group projects in a workspace.
  - name: Contacts
    description: Vendors, crew, and other workspace contacts.
  - name: Tokens
    description: List and revoke API tokens.
  - name: Library
    description: Reusable budget items for a workspace or project.
  - name: Budget
    description: Budget lines, phases, phase data, and totals.
  - name: Transactions
    description: Financial transactions and their items.
  - name: Purchase Orders
    description: Purchase orders, items, approvals, payments, and history.
  - name: Payment Requests
    description: Requests to pay a person or company. A request stays separate from
      the payment that follows.
  - name: Payments
    description: Payments from request through settlement, with linked records and a
      Timeline.
  - name: Documents
    description: Upload documents, read their content, and link them to other resources.
  - name: Search
    description: Search transactions, documents, contacts, and budget lines.
  - name: Comments
    description: Comments within a project.
  - name: Webhook Subscriptions
    description: Subscribe to events and review webhook deliveries.
paths:
  /projects/{projectId}/budget:
    get:
      operationId: budget_get
      summary: Get a budget
      description: Returns the budget's visible phases, totals, lines, and editable
        phase data. Use `path` or `accountId` to select an account and its
        descendants. Use `parentId` to build the line tree.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: path
          in: query
          required: false
          description: Select this account path and its descendants, such as `1100/1110`.
          schema:
            type: string
        - name: accountId
          in: query
          required: false
          description: Select this account number and its descendants. An account number
            used by multiple lines returns `409 account_code_ambiguous`.
          schema:
            type: string
        - name: phase
          in: query
          required: false
          description: Select a visible phase by ID, alias, name, or type. An ambiguous
            value returns `400 validation`.
          schema:
            type: string
        - name: If-None-Match
          in: header
          required: false
          description: A previous `ETag`. Returns `304 Not Modified` when the budget is
            unchanged.
          schema:
            type: string
      responses:
        "200":
          description: The budget document.
          headers:
            ETag:
              description: A value for a later `If-None-Match` request.
              schema:
                type: string
            Cache-Control:
              description: How long the response may be cached.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetDocument"
        "304":
          description: Budget unchanged.
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "413":
          $ref: "#/components/responses/Error413"
        "429":
          $ref: "#/components/responses/Error429"
        "504":
          $ref: "#/components/responses/Error504"
  /projects/{projectId}/budget/totals:
    get:
      operationId: budget_getTotals
      summary: Get budget totals
      description: Returns totals at `computedAt`. Use `phase`, `accountId`, or `path`
        to select part of the budget.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: phase
          in: query
          required: false
          description: Select a phase by ID or type, such as `estimate`.
          schema:
            type: string
          example: estimate
        - name: accountId
          in: query
          required: false
          description: Select this account number and its descendants.
          schema:
            type: string
          example: "1100"
        - name: path
          in: query
          required: false
          description: Select this account path and its descendants, such as `1100/1110`.
          schema:
            type: string
          example: 1100/1110
        - name: If-None-Match
          in: header
          required: false
          description: A previous `ETag`. Returns `304 Not Modified` when the totals are
            unchanged.
          schema:
            type: string
      responses:
        "200":
          description: The budget totals.
          headers:
            ETag:
              schema:
                type: string
            Cache-Control:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetTotals"
        "304":
          description: Totals unchanged.
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "413":
          $ref: "#/components/responses/Error413"
        "429":
          $ref: "#/components/responses/Error429"
        "504":
          $ref: "#/components/responses/Error504"
  /projects/{projectId}/budget/lines:
    get:
      operationId: budget_listLines
      summary: List budget lines
      description: Returns budget lines that match all filters. Use `expand` to
        include contacts, phase totals, or phase data. Use the budget endpoint
        to get the full budget in one response.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: accountId
          in: query
          required: false
          description: Only lines with this account number. An account number may match
            multiple lines.
          schema:
            type: string
          example: "1100"
        - name: path
          in: query
          required: false
          description: Only the line at this account path, such as `1100/1110`. An
            ambiguous path returns `409 account_path_ambiguous`.
          schema:
            type: string
          example: 1100/1110
        - name: tags
          in: query
          required: false
          description: Only lines with these comma-separated tag IDs or names.
          schema:
            type: string
          example: vfx
        - name: tagMode
          in: query
          required: false
          description: How multiple `tags` values are combined.
          schema:
            $ref: "#/components/schemas/TagMode"
        - name: type
          in: query
          required: false
          description: Only lines with these comma-separated types.
          schema:
            type: string
          example: line,account
        - $ref: "#/components/parameters/budgetLineExpand"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
      responses:
        "200":
          description: A page of budget lines.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                additionalProperties: false
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/BudgetLine"
                  nextCursor:
                    $ref: "#/components/schemas/NextCursor"
                  count:
                    type: integer
                    description: Total matching lines; present only when `withCount=true`.
                  truncated:
                    type: boolean
                    description: Whether the page ended before `limit` because some results were
                      unavailable.
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: budget_createLine
      summary: Create a budget line
      description: Creates a budget line under `parentId`, with optional phase data
        keyed by phase ID.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: Idempotency-Key
          in: header
          required: true
          description: A 16 to 255 character key for safe retries. Reusing the key with a
            different request returns `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BudgetLineCreate"
      responses:
        "201":
          description: The created budget line.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLine"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/lines/bulk:
    post:
      operationId: budget_createLinesBulk
      summary: Create budget lines
      description: Creates up to 100 budget lines with optional phase data. If any
        line fails, none are created. Use `Idempotency-Key` to retry safely.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: Idempotency-Key
          in: header
          required: true
          description: A 16 to 255 character key for safe retries. Reusing the key with a
            different request returns `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BudgetLineBulkCreate"
      responses:
        "201":
          description: The created budget lines in request order.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLineBulkCreateResponse"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/lines/phase-data/bulk:
    post:
      operationId: budget_updateLinePhaseDataBulk
      summary: Update phase data for budget lines
      description: Updates up to 500 line and phase entries. If any entry fails, none
        are changed. Use `Idempotency-Key` to retry safely.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: Idempotency-Key
          in: header
          required: true
          description: A 16 to 255 character key for safe retries. Reusing the key with a
            different request returns `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BudgetLinePhaseDataBulkUpsert"
      responses:
        "200":
          description: The updated phase data.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLinePhaseDataBulkUpsertResponse"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/lines/{lineId}:
    get:
      operationId: budget_getLine
      summary: Get a budget line
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: lineId
          in: path
          required: true
          description: The budget line ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/budgetLineExpand"
      responses:
        "200":
          description: The budget line.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLine"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: budget_updateLine
      summary: Update a budget line
      description: Updates a budget line and optional phase data. Omitted fields
        remain unchanged.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: lineId
          in: path
          required: true
          description: The budget line ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BudgetLineUpdate"
      responses:
        "200":
          description: The updated budget line.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLine"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: budget_deleteLine
      summary: Delete a budget line
      description: Deletes a budget line.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: lineId
          in: path
          required: true
          description: The budget line ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Budget line deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/lines/{lineId}/phase-data/{phaseId}:
    put:
      operationId: budget_updateLinePhaseData
      summary: Update phase data for a budget line
      description: Updates one line and phase entry. Omitted fields remain unchanged.
        Null clears a nullable field.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: lineId
          in: path
          required: true
          description: The budget line ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: phaseId
          in: path
          required: true
          description: The phase ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BudgetLinePhaseDataUpsert"
      responses:
        "200":
          description: The updated phase data.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetLinePhaseDataUpsertResponse"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/phases:
    get:
      operationId: budget_listPhases
      summary: List budget phases
      description: Returns the budget's visible and hidden phases.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
      responses:
        "200":
          description: The budget phases.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                additionalProperties: false
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/BudgetPhase"
                  nextCursor:
                    $ref: "#/components/schemas/NextCursor"
                  count:
                    type: integer
                    description: Total results when `withCount=true`.
                  truncated:
                    type: boolean
                    description: Whether the page ended before `limit` because some results were
                      unavailable.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: budget_createPhase
      summary: Create a budget phase
      description: Adds a phase to the budget.
      tags:
        - Budget
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: A 16 to 255 character key for safe retries. Reusing the key with a
            different request returns `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
        - $ref: "#/components/parameters/projectId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - name
              additionalProperties: false
              properties:
                type:
                  $ref: "#/components/schemas/PhaseType"
                name:
                  type: string
                  maxLength: 255
                alias:
                  type: string
                  maxLength: 64
                color:
                  type: string
                  maxLength: 32
                isHidden:
                  type: boolean
                displayDecimals:
                  type:
                    - integer
                    - "null"
                  minimum: 0
                  maximum: 4
                baseCurrencyId:
                  type:
                    - string
                    - "null"
                actualDateStart:
                  type:
                    - string
                    - "null"
                  format: date
                actualDateEnd:
                  type:
                    - string
                    - "null"
                  format: date
                actualStatuses:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualSourceTypes:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualCurrencies:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                    minLength: 3
                    maxLength: 3
                actualContactId:
                  type:
                    - string
                    - "null"
                actualTagIds:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualBudgetLineIds:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                estimateTagIds:
                  type: array
                  items:
                    type: string
                overtimeFactors:
                  type: array
                  items:
                    type: string
                    enum:
                      - qty
                      - x
                committedDateStart:
                  type:
                    - string
                    - "null"
                  format: date
                committedDateEnd:
                  type:
                    - string
                    - "null"
                  format: date
                committedContactId:
                  type:
                    - string
                    - "null"
                committedPhaseIds:
                  type: array
                  items:
                    type: string
                committedPoStatuses:
                  type: array
                  items:
                    type: string
                    enum:
                      - approved
                      - paymentRequested
                      - paymentRejected
                      - paymentProcessing
                derivedFromPhaseId:
                  type: string
                  description: "The estimate phase to use as the starting point. Both phases must
                    have `type: estimate`."
                copyValues:
                  type: boolean
                  description: Whether to copy values from `derivedFromPhaseId`. Defaults to
                    `true`.
                rollupFormula:
                  type: string
                  maxLength: 2000
                  pattern: ^(?:@\{[\w-]+\}|@[\w-]+|[\d\s+\-*/().,%])*$
                  description: A formula for a `rollup` phase. Reference phases as `@{phaseId}`
                    and combine them with `+` or `-`. A rollup without a formula
                    totals 0.
                rollupDisplayMode:
                  type:
                    - string
                    - "null"
                  enum:
                    - value
                    - percent
                    - bars
                    - margin
                    - null
            example:
              type: estimate
              name: Scenario B
              derivedFromPhaseId: ph_1a2b
      responses:
        "201":
          description: The created phase.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetPhase"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/budget/phases/{phaseId}:
    get:
      operationId: budget_getPhase
      summary: Get a budget phase
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: phaseId
          in: path
          required: true
          description: The phase ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The phase.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetPhase"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: budget_updatePhase
      summary: Update a budget phase
      description: Updates a budget phase. Omitted fields remain unchanged.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: phaseId
          in: path
          required: true
          description: The phase ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              minProperties: 1
              properties:
                name:
                  type: string
                  maxLength: 255
                alias:
                  type: string
                  maxLength: 64
                color:
                  type:
                    - string
                    - "null"
                  maxLength: 32
                isHidden:
                  type: boolean
                displayDecimals:
                  type:
                    - integer
                    - "null"
                  minimum: 0
                  maximum: 4
                baseCurrencyId:
                  type:
                    - string
                    - "null"
                actualDateStart:
                  type:
                    - string
                    - "null"
                  format: date
                actualDateEnd:
                  type:
                    - string
                    - "null"
                  format: date
                actualStatuses:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualSourceTypes:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualCurrencies:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                    minLength: 3
                    maxLength: 3
                actualContactId:
                  type:
                    - string
                    - "null"
                actualTagIds:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                actualBudgetLineIds:
                  type:
                    - array
                    - "null"
                  items:
                    type: string
                estimateTagIds:
                  type: array
                  items:
                    type: string
                overtimeFactors:
                  type: array
                  items:
                    type: string
                    enum:
                      - qty
                      - x
                committedDateStart:
                  type:
                    - string
                    - "null"
                  format: date
                committedDateEnd:
                  type:
                    - string
                    - "null"
                  format: date
                committedContactId:
                  type:
                    - string
                    - "null"
                committedPhaseIds:
                  type: array
                  items:
                    type: string
                committedPoStatuses:
                  type: array
                  items:
                    type: string
                    enum:
                      - approved
                      - paymentRequested
                      - paymentRejected
                      - paymentProcessing
                rollupFormula:
                  type:
                    - string
                    - "null"
                  maxLength: 2000
                  pattern: ^(?:@\{[\w-]+\}|@[\w-]+|[\d\s+\-*/().,%])*$
                  description: The formula for a `rollup` phase. Reference phases as `@{phaseId}`
                    and combine them with `+` or `-`. Null clears the formula.
                rollupDisplayMode:
                  type:
                    - string
                    - "null"
                  enum:
                    - value
                    - percent
                    - bars
                    - margin
                    - null
      responses:
        "200":
          description: The updated phase.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BudgetPhase"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: budget_deletePhase
      summary: Delete a budget phase
      description: Deletes the phase and its budget column. Delete estimate phases
        only when removing their data. Rename or reorder a phase to reorganize
        the budget.
      tags:
        - Budget
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: phaseId
          in: path
          required: true
          description: The phase ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Budget phase deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /documents:
    post:
      operationId: documents_upload
      tags:
        - Documents
      summary: Upload a document
      description: Upload a document and optionally link it to targets with
        `metadata.links`. Each target must have a different `kind`. If any link
        fails, the document is not created. This operation is billable. Use
        `Idempotency-Key` to retry safely.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: A 16 to 255 character key for safe retries. Reusing the key with
            different content returns `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/DocumentCreateRequest"
            encoding:
              metadata:
                contentType: text/plain
      responses:
        "201":
          description: The created document and its links.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    get:
      operationId: documents_list
      tags:
        - Documents
      summary: List documents
      description: Returns up to 100 documents per page. Use filters to narrow the results.
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/sort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/withCount"
        - name: folder
          in: query
          required: false
          description: Only documents in this folder.
          schema:
            $ref: "#/components/schemas/Id"
        - name: linkedTo
          in: query
          required: false
          description: Only documents linked to this target. Use `kind:id`, such as
            `transaction:txn_8f2a1c9e`.
          schema:
            type: string
            pattern: ^(project|contact|transaction|payment|purchaseOrder|budgetLine|paymentRequest):.+$
          examples:
            byTransaction:
              value: transaction:txn_8f2a1c9e
        - name: unassigned
          in: query
          required: false
          description: When `true`, only documents with no links.
          schema:
            type: boolean
        - name: project
          in: query
          required: false
          description: Only documents in this project.
          schema:
            $ref: "#/components/schemas/Id"
        - name: status
          in: query
          required: false
          description: Only documents with this processing status.
          schema:
            $ref: "#/components/schemas/DocumentStatus"
        - name: classification
          in: query
          required: false
          description: Only documents with this classification.
          schema:
            type: string
        - name: coarseType
          in: query
          required: false
          description: Only documents in this category.
          schema:
            $ref: "#/components/schemas/DocumentCoarseType"
        - name: q
          in: query
          required: false
          description: Search document names and descriptions.
          schema:
            type: string
      responses:
        "200":
          description: A page of documents.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentCollection"
              examples:
                page:
                  value:
                    data:
                      - id: doc_4b1f0a7c
                        name: vendor-invoice-0425.pdf
                        mimeType: application/pdf
                        size: 184320
                        status: ready
                        workspaceId: ws_71aa
                        projectId: prj_71aa
                        links:
                          - kind: transaction
                            id: txn_8f2a1c9e
                        createdAt: 2026-05-28T14:03:11Z
                        updatedAt: 2026-05-28T14:03:40Z
                    nextCursor: eyJpZCI6ImRvY180YjFmMGE3YyJ9
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /documents/{documentId}:
    get:
      operationId: documents_get
      tags:
        - Documents
      summary: Get a document
      parameters:
        - name: documentId
          in: path
          required: true
          description: The document ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The document.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: documents_update
      tags:
        - Documents
      summary: Update a document
      description: Update the document's name, description, or folder. Use the links
        endpoint to change its links.
      parameters:
        - name: documentId
          in: path
          required: true
          description: The document ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DocumentUpdateRequest"
            examples:
              rename:
                value:
                  name: vendor-invoice-april.pdf
      responses:
        "200":
          description: The updated document.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: documents_delete
      tags:
        - Documents
      summary: Delete a document
      description: Deletes the document. Safe to retry.
      parameters:
        - name: documentId
          in: path
          required: true
          description: The document ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Document deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /documents/{documentId}/content:
    get:
      operationId: documents_getContent
      tags:
        - Documents
      summary: Download a document
      description: Returns the file with its stored `mimeType` as the response
        `Content-Type`.
      parameters:
        - name: documentId
          in: path
          required: true
          description: The document ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The document file.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /documents/{documentId}/links/{kind}:
    parameters:
      - name: documentId
        in: path
        required: true
        description: The document ID.
        schema:
          $ref: "#/components/schemas/Id"
      - name: kind
        in: path
        required: true
        description: The type of target to link.
        schema:
          $ref: "#/components/schemas/DocumentWritableTargetKind"
    put:
      operationId: documents_link
      tags:
        - Documents
      summary: Link a document
      description: Links the document to one target of this kind. Linking the same
        target again has no effect. Set `replace` to change an existing link of
        this kind.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DocumentLinkRequest"
      responses:
        "200":
          description: The document with updated links.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: documents_unlink
      tags:
        - Documents
      summary: Remove a document link
      description: Removes the link for this kind. Safe to retry.
      responses:
        "200":
          description: The document with updated links.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /documents/{documentId}/extraction:
    get:
      operationId: documents_getExtraction
      tags:
        - Documents
      summary: Get extracted document data
      description: Returns the document's classification, extracted fields, line
        items, and confidence scores. Available when the document status is
        `ready`. Returns `404 not_found` while extraction is pending or
        processing. A failed document has no extraction.
      parameters:
        - name: documentId
          in: path
          required: true
          description: The document ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The extracted document data.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentExtraction"
              examples:
                invoice:
                  value:
                    documentId: doc_4b1f0a7c
                    status: ready
                    classification: invoice
                    coarseType: financial
                    extractedAt: 2026-05-28T14:03:40Z
                    fields:
                      invoiceNumber:
                        value: "4471"
                        confidence: 0.98
                      vendorName:
                        value: B&H Photo
                        confidence: 0.95
                      total:
                        value: "1529.00"
                        confidence: 0.91
                      invoiceDate:
                        value: 2026-05-20
                        confidence: 0.88
                    lineItems:
                      - description: Camera body rental - 3 days
                        amount:
                          amount: 75000
                          currency: USD
                        confidence: 0.86
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/rate-packs:
    get:
      operationId: library_listRatePacks
      summary: List rate packs
      description: "List public and workspace-owned rate packs. Deprecated packs
        already in use include `deprecated: true`."
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - $ref: "#/components/parameters/ratePackExpand"
        - name: q
          in: query
          required: false
          description: Search pack names, publishers, and tags.
          schema:
            type: string
        - name: category
          in: query
          required: false
          description: Only rate packs in this category.
          schema:
            type: string
        - name: deprecated
          in: query
          required: false
          description: Filter by deprecation state.
          schema:
            type: boolean
      responses:
        "200":
          description: A page of rate packs.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePackCollection"
              example:
                data:
                  - id: rpk_2a9f
                    slug: iatse-local-871
                    name: IATSE Local 871
                    category: union
                    tags:
                      - union
                      - scripted
                    visibility: PUBLIC
                    isOwned: false
                    deprecated: false
                    enabled: true
                    latestVersion:
                      id: rpv_1
                      effectiveDate: 2026-01-01
                      itemCount: 142
                nextCursor: eyJpZCI6InJwa18yYTlmIn0
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createRatePack
      summary: Create a rate pack
      description: Create a private rate pack for the workspace. The new pack is
        enabled automatically.
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RatePackCreate"
            example:
              name: My Crew Rates
              category: custom
              tags:
                - crew
      responses:
        "201":
          description: The created rate pack.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePack"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/rate-packs/{packId}:
    get:
      operationId: library_getRatePack
      summary: Get a rate pack
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/ratePackExpand"
      responses:
        "200":
          description: The rate pack.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePack"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateRatePack
      summary: Update a rate pack
      description: Update a workspace-owned rate pack. Other packs return `404 not_found`.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RatePackUpdate"
            example:
              name: My Crew Rates 2026
      responses:
        "200":
          description: The updated rate pack.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePack"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteRatePack
      summary: Delete a rate pack
      description: Delete a workspace-owned rate pack. Repeating the request has no
        additional effect.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/rate-packs/{packId}/enablement:
    post:
      operationId: library_enableRatePack
      summary: Enable a rate pack for the workspace
      description: Make a rate pack available to the workspace. Deprecated packs
        return `400 validation`; private packs owned by another workspace return
        `404 not_found`.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The enable link.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePackEnableLink"
              example:
                id: wrp_5
                ratePackId: rpk_2a9f
                enabledAt: 2026-05-28T10:00:00Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_disableRatePack
      summary: Disable a rate pack for the workspace
      description: Remove a rate pack from the workspace. Repeating the request has no
        additional effect.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Disabled.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/rate-packs/{packId}/items:
    get:
      operationId: library_listRatePackItems
      summary: List rate pack items
      description: List current items in an available rate pack.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search item titles and aliases.
          schema:
            type: string
        - name: group
          in: query
          required: false
          description: Only rate pack items in this group.
          schema:
            type: string
        - name: agreement
          in: query
          required: false
          description: Only rate pack items for this agreement.
          schema:
            type: string
        - name: local
          in: query
          required: false
          description: Only rate pack items for this local.
          schema:
            type: string
        - name: unit
          in: query
          required: false
          description: Filter by unit.
          schema:
            type: string
      responses:
        "200":
          description: A page of pack items.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePackItemCollection"
              example:
                data:
                  - id: rpi_9c
                    title: Costume Designer
                    rate:
                      amount: 6500
                      currency: USD
                    unit: Day
                    group: Wardrobe
                    local: "871"
                    labels: []
                nextCursor: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createRatePackItem
      summary: Add a rate pack item
      description: Add an item to a workspace-owned rate pack.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RatePackItemCreate"
            example:
              title: Key Grip
              rate:
                amount: 5800
                currency: USD
              unit: Day
              group: Grip
      responses:
        "201":
          description: The created item.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePackItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/rate-packs/{packId}/items/{itemId}:
    patch:
      operationId: library_updateRatePackItem
      summary: Update a rate pack item
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RatePackItemUpdate"
            example:
              rate:
                amount: 6000
                currency: USD
      responses:
        "200":
          description: The updated item.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RatePackItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteRatePackItem
      summary: Delete a rate pack item
      description: Delete a rate pack item. Repeating the request has no additional effect.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/incentive-packs:
    get:
      operationId: library_listIncentivePacks
      summary: List incentive packs
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - $ref: "#/components/parameters/incentivePackExpand"
        - name: q
          in: query
          required: false
          description: Search incentive packs by name.
          schema:
            type: string
        - name: category
          in: query
          required: false
          description: Only incentive packs in this category.
          schema:
            type: string
        - name: jurisdiction
          in: query
          required: false
          description: Only incentive packs for this jurisdiction.
          schema:
            type: string
        - name: deprecated
          in: query
          required: false
          description: Filter by whether the incentive pack is deprecated.
          schema:
            type: boolean
      responses:
        "200":
          description: A page of incentive packs.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IncentivePackCollection"
              example:
                data:
                  - id: ipk_ga
                    slug: georgia-film-credit
                    name: Georgia Film Tax Credit
                    jurisdiction: US-GA
                    visibility: PUBLIC
                    isOwned: false
                    deprecated: false
                    enabled: true
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/incentive-packs/{packId}:
    get:
      operationId: library_getIncentivePack
      summary: Get an incentive pack
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/incentivePackExpand"
      responses:
        "200":
          description: The incentive pack.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IncentivePack"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/incentive-packs/{packId}/programs:
    get:
      operationId: library_listIncentivePrograms
      summary: List incentive programs
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - name: jurisdiction
          in: query
          required: false
          description: Only programs for this jurisdiction.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Only programs with this status.
          schema:
            type: string
            enum:
              - published
              - blocked
              - deprecated
      responses:
        "200":
          description: A page of incentive programs.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IncentiveProgramCollection"
              example:
                data:
                  - id: ipr_base
                    name: Base Transferable Credit
                    incentiveType: tax-credit
                    incentiveStructure: transferable
                    status: published
                    currentVersionId: ipv_2026
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/incentive-packs/{packId}/enablement:
    post:
      operationId: library_enableIncentivePack
      summary: Enable an incentive pack for the workspace
      description: Make an incentive pack available to the workspace. Deprecated packs
        return `400 validation`; private packs owned by another workspace return
        `404 not_found`.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The enable link.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IncentivePackEnableLink"
              example:
                id: wip_3
                incentivePackId: ipk_ga
                enabledAt: 2026-05-28T10:00:00Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_disableIncentivePack
      summary: Disable an incentive pack for the workspace
      description: Remove an incentive pack from the workspace. Repeating the request
        has no additional effect.
      tags:
        - Library
      parameters:
        - name: packId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Disabled.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/fringes:
    get:
      operationId: library_listFringes
      summary: List fringes
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search fringe names.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted fringes.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of workspace fringes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FringeCollection"
              example:
                data:
                  - id: frg_pr
                    name: Payroll Tax
                    description: Employer payroll tax
                    calculationType: percent
                    rate: 7.65
                    cutoff: null
                    fringeGroupIds: []
                    color: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createFringe
      summary: Create a fringe
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeWrite"
            example:
              name: Payroll Tax
              description: Employer payroll tax
              calculationType: percent
              rate: 7.65
      responses:
        "201":
          description: The created fringe.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fringe"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/fringes/{fringeId}:
    get:
      operationId: library_getFringe
      summary: Get a fringe
      tags:
        - Library
      parameters:
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fringe"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateFringe
      summary: Update a fringe
      tags:
        - Library
      parameters:
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeWrite"
            example:
              rate: 8
      responses:
        "200":
          description: The updated fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fringe"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteFringe
      summary: Delete a fringe
      description: Delete a workspace fringe. Project fringes created from it remain
        available.
      tags:
        - Library
      parameters:
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/globals:
    get:
      operationId: library_listGlobals
      summary: List globals
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search global names.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted globals.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of workspace globals.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GlobalCollection"
              example:
                data:
                  - id: gbl_days
                    symbol: SHOOT_DAYS
                    description: Shoot Days
                    formula: "35"
                    unit: Day
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createGlobal
      summary: Create a global
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GlobalWrite"
            example:
              symbol: SHOOT_DAYS
              description: Shoot Days
              formula: "35"
              unit: Day
      responses:
        "201":
          description: The created global.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Global"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/globals/{globalId}:
    get:
      operationId: library_getGlobal
      summary: Get a global
      tags:
        - Library
      parameters:
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Global"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateGlobal
      summary: Update a global
      tags:
        - Library
      parameters:
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GlobalWrite"
            example:
              formula: "40"
      responses:
        "200":
          description: The updated global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Global"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteGlobal
      summary: Delete a global
      tags:
        - Library
      parameters:
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/currencies:
    get:
      operationId: library_listCurrencies
      summary: List currencies
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search currency names and codes.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted currencies.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of workspace currencies.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CurrencyCollection"
              example:
                data:
                  - id: cur_gbp
                    code: GBP
                    name: British Pound
                    symbol: £
                    rateToUSD: 1.27
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createCurrency
      summary: Create a currency
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CurrencyWrite"
            example:
              code: GBP
              name: British Pound
              symbol: £
              rateToUSD: 1.27
      responses:
        "201":
          description: The created currency.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Currency"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/currencies/{currencyId}:
    get:
      operationId: library_getCurrency
      summary: Get a currency
      tags:
        - Library
      parameters:
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Currency"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateCurrency
      summary: Update a currency
      tags:
        - Library
      parameters:
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CurrencyWrite"
            example:
              rateToUSD: 1.31
      responses:
        "200":
          description: The updated currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Currency"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteCurrency
      summary: Delete a currency
      tags:
        - Library
      parameters:
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/fringe-groups:
    get:
      operationId: library_listFringeGroups
      summary: List fringe groups
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search fringe group names.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted fringe groups.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of workspace fringe groups.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FringeGroupCollection"
              example:
                data:
                  - id: frt_union
                    name: Union
                    color: blue
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createFringeGroup
      summary: Create a fringe group
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeGroupWrite"
            example:
              name: Union
              color: blue
      responses:
        "201":
          description: The created fringe group.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FringeGroup"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/fringe-groups/{fringeGroupId}:
    get:
      operationId: library_getFringeGroup
      summary: Get a fringe group
      tags:
        - Library
      parameters:
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The fringe group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FringeGroup"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateFringeGroup
      summary: Update a fringe group
      tags:
        - Library
      parameters:
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeGroupWrite"
            example:
              color: green
      responses:
        "200":
          description: The updated fringe group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FringeGroup"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteFringeGroup
      summary: Delete a fringe group
      tags:
        - Library
      parameters:
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/tags:
    get:
      operationId: library_listTags
      summary: List tags
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search tag names.
          schema:
            type: string
        - name: eligibilityKey
          in: query
          required: false
          description: Only tags with this eligibility key.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted tags.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of tags.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagCollection"
              example:
                data:
                  - id: tag_atl
                    name: Atlanta
                    color: orange
                    createdAt: 2026-01-02T08:00:00Z
                    updatedAt: 2026-01-02T08:00:00Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createTag
      summary: Create a workspace tag
      description: Create a workspace tag. `color` accepts a supported display color
        or `null`.
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagCreate"
            example:
              name: Atlanta
              color: orange
      responses:
        "201":
          description: The created tag.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tag"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/tags/{tagId}:
    get:
      operationId: library_getTag
      summary: Get a workspace tag
      tags:
        - Library
      parameters:
        - name: tagId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The tag.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tag"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateTag
      summary: Update a workspace tag
      tags:
        - Library
      parameters:
        - name: tagId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagUpdate"
            example:
              color: green
      responses:
        "200":
          description: The updated tag.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tag"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteTag
      summary: Delete a workspace tag
      description: Delete a tag. Existing historical references remain available.
      tags:
        - Library
      parameters:
        - name: tagId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /library/units:
    get:
      operationId: library_listUnits
      summary: List units
      description: List built-in and workspace units. Built-in units are read-only.
      tags:
        - Library
      parameters:
        - name: q
          in: query
          required: false
          description: Search unit names and abbreviations.
          schema:
            type: string
      responses:
        "200":
          description: All units.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UnitCollection"
              example:
                data:
                  - id: Day
                    label: Day
                    isCustom: false
                  - id: cun_box
                    label: Box Rental
                    isCustom: true
                    createdAt: 2026-03-01T08:00:00Z
                    updatedAt: 2026-03-01T08:00:00Z
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_createUnit
      summary: Create a unit
      description: Create a workspace unit. Built-in units cannot be changed.
      tags:
        - Library
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UnitCreate"
            example:
              label: Box Rental
      responses:
        "201":
          description: The created unit.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Unit"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /library/units/{unitId}:
    get:
      operationId: library_getUnit
      summary: Get a unit
      description: Get a built-in or workspace unit.
      tags:
        - Library
      parameters:
        - name: unitId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: The unit.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Unit"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateUnit
      summary: Update a unit
      tags:
        - Library
      parameters:
        - name: unitId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UnitUpdate"
            example:
              label: Box Rental (weekly)
      responses:
        "200":
          description: The updated unit.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Unit"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteUnit
      summary: Delete a unit
      tags:
        - Library
      parameters:
        - name: unitId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/incentives:
    get:
      operationId: library_listProjectIncentives
      summary: List project incentives
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/projectIncentiveExpand"
        - name: isApplied
          in: query
          required: false
          description: Filter by whether the incentive is applied to the project.
          schema:
            type: boolean
        - name: jurisdiction
          in: query
          required: false
          description: Only project incentives for this jurisdiction.
          schema:
            type: string
      responses:
        "200":
          description: A page of project incentives.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectIncentiveCollection"
              example:
                data:
                  - id: inc_ga1
                    name: Georgia Base Credit
                    sourceType: saturation
                    sourceIncentiveVersionId: ipv_2026
                    isApplied: true
                    amount:
                      amount: 1250000
                      currency: USD
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_addProjectIncentive
      summary: Add an incentive to a project
      description: Add the published version of an available incentive program.
        Unpublished or deprecated incentives return `400 validation`.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectIncentiveAdd"
            example:
              programId: ipr_base
      responses:
        "200":
          description: The existing project incentive.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectIncentive"
        "201":
          description: The created project incentive.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectIncentive"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/incentives/{incentiveId}:
    get:
      operationId: library_getProjectIncentive
      summary: Get a project incentive
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: incentiveId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/projectIncentiveExpand"
      responses:
        "200":
          description: The project incentive.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectIncentive"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateProjectIncentive
      summary: Update a project incentive
      description: Update the supplied incentive fields.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: incentiveId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectIncentiveUpdate"
            example:
              isApplied: false
      responses:
        "200":
          description: The updated project incentive.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectIncentive"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteProjectIncentive
      summary: Remove a project incentive
      description: Remove an incentive from a project. Adding it again restores its
        previous settings.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: incentiveId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Removed.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/fringes:
    get:
      operationId: library_listProjectFringes
      summary: List project fringes
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/libraryExpand"
        - name: sourceId
          in: query
          required: false
          description: Filter by the workspace fringe used to create the project fringe.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: A page of project fringes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeCollection"
              example:
                data:
                  - id: frg_project1
                    name: Payroll Tax
                    description: Employer payroll tax
                    calculationType: percent
                    rate: 8
                    cutoff: null
                    fringeGroupIds: []
                    color: null
                    sourceType: workspace
                    sourceId: frg_pr
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_addProjectFringe
      summary: Add a fringe to a project
      description: Add a workspace fringe to a project. Adding it again keeps project
        edits. Use `reset=true` to restore workspace values.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: reset
          in: query
          required: false
          description: Restore workspace values and replace project edits.
          schema:
            type: boolean
            default: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - sourceId
              properties:
                sourceId:
                  $ref: "#/components/schemas/Id"
            example:
              sourceId: frg_pr
      responses:
        "200":
          description: The existing project fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringe"
        "201":
          description: The created project fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringe"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/fringes/{fringeId}:
    get:
      operationId: library_getProjectFringe
      summary: Get a project fringe
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/libraryExpand"
      responses:
        "200":
          description: The project fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringe"
              example:
                id: frg_project1
                name: Payroll Tax
                description: Employer payroll tax
                calculationType: percent
                rate: 8
                cutoff: null
                fringeGroupIds: []
                color: null
                sourceType: workspace
                sourceId: frg_pr
                source:
                  id: frg_pr
                  name: Payroll Tax
                  description: Employer payroll tax
                  calculationType: percent
                  rate: 7.65
                  cutoff: null
                  fringeGroupIds: []
                  color: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateProjectFringe
      summary: Update a project fringe
      description: Update the supplied project fringe fields.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeWrite"
            example:
              rate: 8.5
      responses:
        "200":
          description: The updated project fringe.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringe"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteProjectFringe
      summary: Remove a project fringe
      description: Remove a fringe from a project. Adding it again restores its
        previous settings unless `reset=true`.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Removed.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/globals:
    get:
      operationId: library_listProjectGlobals
      summary: List project globals
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/libraryExpand"
        - name: sourceId
          in: query
          required: false
          description: Only globals copied from this workspace global.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: A page of project globals.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectGlobalCollection"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_addProjectGlobal
      summary: Add a global to a project
      description: Add a workspace global to a project. Adding it again keeps project
        edits. Use `reset=true` to restore workspace values.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: reset
          in: query
          required: false
          description: Restore workspace values and replace project edits.
          schema:
            type: boolean
            default: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - sourceId
              properties:
                sourceId:
                  $ref: "#/components/schemas/Id"
            example:
              sourceId: gbl_days
      responses:
        "200":
          description: The existing project global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectGlobal"
        "201":
          description: The created project global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectGlobal"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/globals/{globalId}:
    get:
      operationId: library_getProjectGlobal
      summary: Get a project global
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/libraryExpand"
      responses:
        "200":
          description: The project global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectGlobal"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateProjectGlobal
      summary: Update a project global
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GlobalWrite"
            example:
              formula: "38"
      responses:
        "200":
          description: The updated project global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectGlobal"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteProjectGlobal
      summary: Remove a project global
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: globalId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Removed.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/currencies:
    get:
      operationId: library_listProjectCurrencies
      summary: List project currencies
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/libraryExpand"
        - name: sourceId
          in: query
          required: false
          description: Only currencies copied from this workspace currency.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: A page of project currencies.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCurrencyCollection"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_addProjectCurrency
      summary: Add a currency to a project
      description: Add a workspace currency to a project. Adding it again keeps
        project edits. Use `reset=true` to restore workspace values.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: reset
          in: query
          required: false
          description: Restore workspace values and replace project edits.
          schema:
            type: boolean
            default: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - sourceId
              properties:
                sourceId:
                  $ref: "#/components/schemas/Id"
            example:
              sourceId: cur_gbp
      responses:
        "200":
          description: The existing project currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCurrency"
        "201":
          description: The created project currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCurrency"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/currencies/{currencyId}:
    get:
      operationId: library_getProjectCurrency
      summary: Get a project currency
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/libraryExpand"
      responses:
        "200":
          description: The project currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCurrency"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateProjectCurrency
      summary: Update a project currency
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CurrencyWrite"
            example:
              rateToUSD: 1.33
      responses:
        "200":
          description: The updated project currency.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCurrency"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteProjectCurrency
      summary: Remove a project currency
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: currencyId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Removed.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/fringe-groups:
    get:
      operationId: library_listProjectFringeGroups
      summary: List project fringe groups
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/libraryExpand"
        - name: sourceId
          in: query
          required: false
          description: Only fringe groups copied from this workspace fringe group.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: A page of project fringe groups.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeGroupCollection"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: library_addProjectFringeGroup
      summary: Add a fringe group to a project
      description: Add a workspace Fringe Group to a project. Adding it again keeps
        project edits. Use `reset=true` to restore workspace values.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: reset
          in: query
          required: false
          description: Restore workspace values and replace project edits.
          schema:
            type: boolean
            default: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - sourceId
              properties:
                sourceId:
                  $ref: "#/components/schemas/Id"
            example:
              sourceId: frt_union
      responses:
        "200":
          description: The existing project Fringe Group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeGroup"
        "201":
          description: The created project Fringe Group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeGroup"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/fringe-groups/{fringeGroupId}:
    get:
      operationId: library_getProjectFringeGroup
      summary: Get a project fringe group
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/libraryExpand"
      responses:
        "200":
          description: The project Fringe Group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeGroup"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: library_updateProjectFringeGroup
      summary: Update a project fringe group
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FringeGroupWrite"
            example:
              color: red
      responses:
        "200":
          description: The updated project Fringe Group.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectFringeGroup"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: library_deleteProjectFringeGroup
      summary: Remove a project fringe group
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - name: fringeGroupId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Removed.
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/library/tags:
    get:
      operationId: library_listProjectTags
      summary: List project tags
      description: List tags used in the project.
      tags:
        - Library
      parameters:
        - $ref: "#/components/parameters/projectId"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: A page of project tags.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagCollection"
              example:
                data:
                  - id: tag_atl
                    name: Atlanta
                    color: orange
                    createdAt: 2026-01-02T08:00:00Z
                    updatedAt: 2026-01-02T08:00:00Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects:
    get:
      operationId: projects_list
      tags:
        - Projects
      summary: List projects
      description: List projects you can access. Results are paginated and exclude
        deleted projects by default.
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/sort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/withCount"
        - name: status
          in: query
          required: false
          description: Filter by status. Separate multiple values with commas (for
            example, `active,archived`).
          schema:
            type: string
            example: active
        - name: spaceId
          in: query
          required: false
          description: Only projects filed under this space.
          schema:
            $ref: "#/components/schemas/Id"
        - name: q
          in: query
          required: false
          description: Search project names and slugs.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted projects.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of projects.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectList"
              example:
                data:
                  - id: prj_8f2a1c9e
                    slug: q3-feature-doc
                    name: Q3 Feature Doc
                    emoji: 🎬
                    image: null
                    status: active
                    summary: A short documentary on Q3 features.
                    spaceId: spc_1a2b3c
                    createdAt: 2026-05-01T12:00:00Z
                    updatedAt: 2026-05-20T09:30:00Z
                nextCursor: eyJpZCI6InByal84ZjJhMWM5ZSJ9
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: projects_create
      tags:
        - Projects
      summary: Create a project
      description: Create a project in the workspace. Read-only fields return `422
        field_read_only` when supplied.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectCreate"
            example:
              name: Q3 Feature Doc
              emoji: 🎬
              spaceId: spc_1a2b3c
      responses:
        "201":
          description: The created project.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProjectCreated"
              example:
                id: prj_8f2a1c9e
                slug: q3-feature-doc
                name: Q3 Feature Doc
                emoji: 🎬
                image: null
                status: active
                summary: null
                spaceId: spc_1a2b3c
                createdAt: 2026-05-29T10:00:00Z
                updatedAt: 2026-05-29T10:00:00Z
                defaultBudget:
                  budgetId: bud_8f2a1c9e
                  estimatePhaseId: phs_estimate
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "423":
          $ref: "#/components/responses/Error423"
        "429":
          $ref: "#/components/responses/Error429"
        "503":
          $ref: "#/components/responses/Error503"
  /projects/{projectId}:
    parameters:
      - name: projectId
        in: path
        required: true
        description: Project ID or slug.
        schema:
          type: string
    get:
      operationId: projects_get
      tags:
        - Projects
      summary: Get a project
      description: Get a project by ID or slug.
      responses:
        "200":
          description: The project.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Project"
              example:
                id: prj_8f2a1c9e
                slug: q3-feature-doc
                name: Q3 Feature Doc
                emoji: 🎬
                image: null
                status: active
                summary: A short documentary on Q3 features.
                spaceId: spc_1a2b3c
                createdAt: 2026-05-01T12:00:00Z
                updatedAt: 2026-05-20T09:30:00Z
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: projects_update
      tags:
        - Projects
      summary: Update a project
      description: Update the supplied project fields.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectUpdate"
            example:
              name: Q3 Feature Doc (final)
              status: archived
      responses:
        "200":
          description: The updated project.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Project"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /spaces:
    get:
      operationId: spaces_list
      tags:
        - Spaces
      summary: List spaces
      description: List spaces in the workspace.
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/sort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/withCount"
        - name: parentId
          in: query
          required: false
          description: Only spaces directly nested under this parent space.
          schema:
            $ref: "#/components/schemas/Id"
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted spaces.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of spaces.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SpaceList"
              example:
                data:
                  - id: spc_1a2b3c
                    slug: features
                    name: Features
                    image: null
                    parentId: null
                    archived: false
                    createdAt: 2026-04-01T12:00:00Z
                    updatedAt: 2026-04-01T12:00:00Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: spaces_create
      tags:
        - Spaces
      summary: Create a space
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpaceCreate"
            example:
              name: Features
      responses:
        "201":
          description: The created space.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Space"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /spaces/{spaceId}:
    parameters:
      - name: spaceId
        in: path
        required: true
        description: Space ID.
        schema:
          $ref: "#/components/schemas/Id"
    patch:
      operationId: spaces_update
      tags:
        - Spaces
      summary: Update a space
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpaceUpdate"
            example:
              name: Feature Docs
              archived: true
      responses:
        "200":
          description: The updated space.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Space"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: spaces_delete
      tags:
        - Spaces
      summary: Delete a space
      description: Delete a space. Its projects become ungrouped. Repeating the
        request has no additional effect.
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /contacts:
    get:
      operationId: contacts_list
      tags:
        - Contacts
      summary: List contacts
      description: List contacts in the workspace. Use `expand` to include accessible
        documents or transactions.
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/sort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/contactExpand"
        - $ref: "#/components/parameters/withCount"
        - name: q
          in: query
          required: false
          description: Search contact names, companies, and email addresses.
          schema:
            type: string
        - name: type
          in: query
          required: false
          description: Filter by one or more comma-separated contact types.
          schema:
            type: string
            example: contractor
        - name: tags
          in: query
          required: false
          description: Comma-separated tag handles to filter by.
          schema:
            type: string
        - name: tagMode
          in: query
          required: false
          description: How `tags` combine.
          schema:
            type: string
            enum:
              - any
              - all
              - none
            default: any
        - name: track1099
          in: query
          required: false
          description: Filter by 1099 tracking status.
          schema:
            type: boolean
        - name: hasTaxId
          in: query
          required: false
          description: Filter by whether a tax ID is on file.
          schema:
            type: boolean
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted contacts.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of contacts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactList"
              example:
                data:
                  - id: con_5c4d3e2f
                    displayName: Aerial Imaging LLC
                    name: Jordan Lee
                    company: Aerial Imaging LLC
                    title: Drone Operator
                    type: company
                    email: jordan@aerialimaging.example
                    phone: null
                    address: null
                    website: null
                    instagram: null
                    imdb: null
                    rate:
                      amount: 85000
                      currency: USD
                    track1099: true
                    taxIdLast4: "4821"
                    hasTaxId: true
                    notes: null
                    createdAt: 2026-03-10T08:00:00Z
                    updatedAt: 2026-05-02T16:45:00Z
                nextCursor: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: contacts_create
      tags:
        - Contacts
      summary: Create a contact
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactCreate"
            example:
              name: Jordan Lee
              company: Aerial Imaging LLC
              type: company
              email: jordan@aerialimaging.example
              track1099: true
              rate:
                amount: 85000
                currency: USD
      responses:
        "201":
          description: The created contact.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /contacts/{contactId}:
    parameters:
      - name: contactId
        in: path
        required: true
        description: Contact ID.
        schema:
          $ref: "#/components/schemas/Id"
    get:
      operationId: contacts_get
      tags:
        - Contacts
      summary: Get a contact
      parameters:
        - $ref: "#/components/parameters/contactExpand"
      responses:
        "200":
          description: The contact.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: contacts_update
      tags:
        - Contacts
      summary: Update a contact
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactUpdate"
            example:
              title: Senior Drone Operator
              track1099: false
      responses:
        "200":
          description: The updated contact.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: contacts_delete
      tags:
        - Contacts
      summary: Delete a contact
      description: Delete a contact. Repeating the request has no additional effect.
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/comments:
    parameters:
      - name: projectId
        in: path
        required: true
        schema:
          $ref: "#/components/schemas/Id"
    get:
      operationId: comments_list
      tags:
        - Comments
      summary: List comments
      description: List comments in a project. Use `targetKind` and `targetId`
        together to filter by resource.
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/sort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/withCount"
        - name: targetKind
          in: query
          required: false
          description: Resource type. Use with `targetId`.
          schema:
            $ref: "#/components/schemas/CommentTargetKind"
        - name: targetId
          in: query
          required: false
          description: Resource ID. Use with `targetKind`.
          schema:
            $ref: "#/components/schemas/Id"
        - name: threadId
          in: query
          required: false
          description: Only replies under this root comment.
          schema:
            $ref: "#/components/schemas/Id"
        - name: resolved
          in: query
          required: false
          description: Filter by resolution state.
          schema:
            type: boolean
      responses:
        "200":
          description: A page of comments.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CommentList"
              example:
                data:
                  - id: cmt_7a8b9c
                    projectId: prj_8f2a1c9e
                    threadId: null
                    target:
                      kind: budgetLine
                      id: bud_1234abcd
                    authorId: usr_a1b2c3
                    authorName: Sam Rivera
                    content: Can we confirm the drone day rate here?
                    resolved: false
                    createdAt: 2026-05-21T14:00:00Z
                    updatedAt: 2026-05-21T14:00:00Z
                nextCursor: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: comments_create
      tags:
        - Comments
      summary: Create a comment
      description: Add a comment to a project resource you can edit.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Unique request key, 16 to 255 characters. Retrying the same request
            returns the first response. Missing or invalid keys return `400
            validation`; reuse with a different body returns `409
            idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CommentCreate"
            example:
              content: Can we confirm the drone day rate here?
              target:
                kind: budgetLine
                id: bud_1234abcd
      responses:
        "201":
          description: The created comment.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Comment"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /projects/{projectId}/comments/{commentId}:
    parameters:
      - name: projectId
        in: path
        required: true
        schema:
          $ref: "#/components/schemas/Id"
      - name: commentId
        in: path
        required: true
        description: Comment ID.
        schema:
          $ref: "#/components/schemas/Id"
    patch:
      operationId: comments_update
      tags:
        - Comments
      summary: Update a comment
      description: Edit the comment body or resolution. Only the author can edit the body.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CommentUpdate"
            example:
              resolved: true
      responses:
        "200":
          description: The updated comment.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Comment"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: comments_delete
      tags:
        - Comments
      summary: Delete a comment
      description: Delete a comment and its replies. Repeating the request has no
        additional effect.
      responses:
        "204":
          description: Deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /me:
    get:
      operationId: me_get
      tags:
        - Meta
      summary: Get the current identity
      description: Returns the identity and workspaces associated with the token.
      responses:
        "200":
          description: The current identity and workspaces.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Me"
              example:
                id: usr_4f1a8c2e
                type: user
                email: producer@example.com
                name: Dana Producer
                workspaces:
                  - workspaceId: ws_2b9d7a1f
                    workspaceName: Paradigm Pictures
                    workspaceRole: admin
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "429":
          $ref: "#/components/responses/Error429"
  /payment-requests:
    get:
      operationId: payment-requests_list
      summary: List payment requests
      description: Returns payment requests. Use `expand` to include related records.
      tags:
        - Payment Requests
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - name: status
          in: query
          description: Only payment requests with this status.
          schema:
            $ref: "#/components/schemas/PaymentRequestStatus"
        - name: projectId
          in: query
          description: Only payment requests for this project.
          schema:
            $ref: "#/components/schemas/Id"
        - name: purchaseOrderId
          in: query
          description: Only payment requests linked to this purchase order.
          schema:
            $ref: "#/components/schemas/Id"
        - name: contactId
          in: query
          description: Only payment requests for this contact.
          schema:
            $ref: "#/components/schemas/Id"
        - name: expand
          in: query
          schema:
            type: array
            items:
              $ref: "#/components/schemas/PaymentRequestExpand"
          style: form
          explode: false
          description: Related records to include, separated by commas.
      responses:
        "200":
          description: Payment requests.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentRequestList"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
  /payment-requests/{paymentRequestId}:
    get:
      operationId: payment-requests_get
      summary: Get a payment request
      description: Returns a payment request. Use `expand` to include related records.
      tags:
        - Payment Requests
      parameters:
        - name: paymentRequestId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: expand
          in: query
          schema:
            type: array
            items:
              $ref: "#/components/schemas/PaymentRequestExpand"
          style: form
          explode: false
          description: Related records to include, separated by commas.
      responses:
        "200":
          description: The payment request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentRequest"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
  /payments:
    get:
      operationId: payments_list
      summary: List payments
      description: Returns payments.
      tags:
        - Payments
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - name: status
          in: query
          description: Only payments with this status.
          schema:
            $ref: "#/components/schemas/PaymentStatus"
        - name: projectId
          in: query
          description: Only payments for this project.
          schema:
            $ref: "#/components/schemas/Id"
        - name: purchaseOrderId
          in: query
          description: Only payments linked to this purchase order.
          schema:
            $ref: "#/components/schemas/Id"
        - name: paymentRequestId
          in: query
          description: Only payments created from this payment request.
          schema:
            $ref: "#/components/schemas/Id"
        - name: contactId
          in: query
          description: Only payments for this contact.
          schema:
            $ref: "#/components/schemas/Id"
        - name: expand
          in: query
          schema:
            type: array
            items:
              $ref: "#/components/schemas/PaymentExpand"
          style: form
          explode: false
          description: Related records to include, separated by commas.
      responses:
        "200":
          description: Payments.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentList"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
  /payments/{paymentId}:
    get:
      operationId: payments_get
      summary: Get a payment
      description: Returns a payment. Use `expand` to include related records.
      tags:
        - Payments
      parameters:
        - name: paymentId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: expand
          in: query
          schema:
            type: array
            items:
              $ref: "#/components/schemas/PaymentExpand"
          style: form
          explode: false
          description: Related records to include, separated by commas.
      responses:
        "200":
          description: The payment.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Payment"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
  /payments/{paymentId}/timeline:
    get:
      operationId: payments_getTimeline
      summary: Get a payment timeline
      description: Returns payment history, newest first.
      tags:
        - Payments
      parameters:
        - name: paymentId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
      responses:
        "200":
          description: Payment history.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentTimelinePage"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
  /purchase-orders:
    get:
      operationId: purchase-orders_list
      summary: List purchase orders
      description: Returns purchase orders you can access. Deleted orders are excluded
        by default.
      tags:
        - Purchase Orders
      parameters:
        - name: projectId
          in: query
          required: false
          description: Project ID or slug. Use `none` for unassigned purchase orders.
          schema:
            type: string
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/purchaseOrderSort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/purchaseOrderExpand"
        - $ref: "#/components/parameters/withCount"
        - name: status
          in: query
          required: false
          description: Purchase order status.
          schema:
            $ref: "#/components/schemas/PurchaseOrderStatus"
        - name: contactId
          in: query
          required: false
          description: Vendor contact ID.
          schema:
            type: string
        - name: budgetLineId
          in: query
          required: false
          description: Budget line ID.
          schema:
            type: string
        - name: number
          in: query
          required: false
          description: Purchase order number. Matching is exact.
          schema:
            type: string
        - name: q
          in: query
          required: false
          description: Search purchase order names.
          schema:
            type: string
        - name: includeDeleted
          in: query
          required: false
          description: Include deleted purchase orders. Defaults to `false`.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: A page of purchase orders.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrderList"
              examples:
                page:
                  value:
                    data:
                      - id: po_8f2a1c9e
                        workspaceId: ws_3b1
                        projectId: prj_demo
                        number: PO-0042
                        name: Camera package rental
                        status: pending
                        contactId: con_77a
                        budgetLineId: bud_5510
                        dueDate: 2026-05-20
                        amount:
                          amount: 152900
                          currency: USD
                        createdAt: 2026-05-18T14:02:11.000Z
                        updatedAt: 2026-05-20T09:31:00.000Z
                    nextCursor: eyJpZCI6InBvXzhmMmExYzllIn0
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: purchase-orders_create
      summary: Create a purchase order
      description: Creates a draft purchase order. Use `projectId` to assign it to a
        project. Requires an `Idempotency-Key`.
      tags:
        - Purchase Orders
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key with the same body
            returns the first result. Reusing it with a different body returns
            `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
        - $ref: "#/components/parameters/purchaseOrderExpand"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PurchaseOrderCreate"
            examples:
              create:
                value:
                  number: PO-0042
                  name: Camera package rental
                  contactId: con_77a
                  budgetLineId: bud_5510
                  dueDate: 2026-05-20
                  items:
                    - description: Alexa Mini LF body
                      qty: 5
                      unit: day
                      rate: 25000
      responses:
        "201":
          description: The created purchase order (status `draft`).
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
              examples:
                created:
                  value:
                    id: po_8f2a1c9e
                    workspaceId: ws_3b1
                    projectId: prj_demo
                    number: PO-0042
                    name: Camera package rental
                    status: draft
                    contactId: con_77a
                    budgetLineId: bud_5510
                    dueDate: 2026-05-20
                    createdById: usr_aa1
                    createdAt: 2026-05-18T14:02:11.000Z
                    updatedAt: 2026-05-18T14:02:11.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}:
    get:
      operationId: purchase-orders_get
      summary: Get a purchase order
      description: Returns a purchase order you can access. Otherwise returns `404
        not_found`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/purchaseOrderExpand"
      responses:
        "200":
          description: The purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: purchase-orders_update
      summary: Update a purchase order
      description: Updates a draft or rejected purchase order. Other statuses return
        `409 po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/purchaseOrderExpand"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PurchaseOrderUpdate"
            examples:
              rename:
                value:
                  name: Camera package rental (updated)
                  notes: Net-45
      responses:
        "200":
          description: The updated purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: purchase-orders_delete
      summary: Delete a purchase order
      description: Deletes a draft purchase order. Other statuses return `409
        po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted. No content.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/submit:
    post:
      operationId: purchase-orders_submit
      summary: Submit a purchase order for approval
      description: Submits a draft or rejected purchase order for approval. Requires
        an `Idempotency-Key`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key returns the first
            submission result.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      responses:
        "200":
          description: The submitted purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
        "503":
          $ref: "#/components/responses/Error503"
  /purchase-orders/{purchaseOrderId}/cancel-submission:
    post:
      operationId: purchase-orders_cancelSubmission
      summary: Cancel a pending submission
      description: Cancels a pending approval and returns the purchase order to
        `draft`. Other statuses return `409 po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The purchase order back in `draft`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
              examples:
                cancelled:
                  value:
                    id: po_8f2a1c9e
                    workspaceId: ws_3b1
                    projectId: prj_demo
                    status: draft
                    updatedAt: 2026-05-18T14:10:00.000Z
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/void:
    post:
      operationId: purchase-orders_void
      summary: Void a purchase order
      description: Voids an approved or actualizing purchase order. Other statuses
        return `409 po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The voided purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
              examples:
                voided:
                  value:
                    id: po_8f2a1c9e
                    workspaceId: ws_3b1
                    projectId: prj_demo
                    status: void
                    updatedAt: 2026-05-21T16:00:00.000Z
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/mark-paid:
    post:
      operationId: purchase-orders_markPaid
      summary: Mark a purchase order as paid
      description: Marks an approved or actualizing purchase order as paid. The
        purchase order must have a linked transaction.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The paid purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
              examples:
                paid:
                  value:
                    id: po_8f2a1c9e
                    workspaceId: ws_3b1
                    projectId: prj_demo
                    status: paid
                    updatedAt: 2026-05-21T18:00:00.000Z
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/transactions/{transactionId}:
    parameters:
      - name: purchaseOrderId
        in: path
        required: true
        schema:
          $ref: "#/components/schemas/Id"
      - name: transactionId
        in: path
        required: true
        schema:
          $ref: "#/components/schemas/Id"
    put:
      operationId: purchase-orders_linkTransaction
      tags:
        - Purchase Orders
      summary: Link a transaction to a purchase order
      responses:
        "200":
          description: The linked purchase order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
    delete:
      operationId: purchase-orders_unlinkTransaction
      tags:
        - Purchase Orders
      summary: Unlink a transaction from a purchase order
      responses:
        "200":
          description: The purchase order after unlinking.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrder"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
  /purchase-orders/{purchaseOrderId}/timeline:
    get:
      operationId: purchase-orders_getTimeline
      summary: Get the purchase order timeline
      description: Returns purchase-order history, newest first.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
      responses:
        "200":
          description: Purchase order history, newest first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrderTimelinePage"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/items:
    get:
      operationId: purchase-orders_listItems
      summary: List purchase order items
      description: Returns the items in a purchase order.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
      responses:
        "200":
          description: A page of purchase-order items.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrderItemList"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: purchase-orders_createItem
      summary: Add a purchase order item
      description: Adds an item to a draft or rejected purchase order. Other statuses
        return `409 po_invalid_status`. Requires an `Idempotency-Key`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key with the same body
            returns the first result. Reusing it with a different body returns
            `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PurchaseOrderItemWrite"
            examples:
              create:
                value:
                  description: Alexa Mini LF body
                  budgetLineId: bud_5510
                  qty: 5
                  unit: day
                  rate: 25000
      responses:
        "201":
          description: The created item.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrderItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /purchase-orders/{purchaseOrderId}/items/{itemId}:
    patch:
      operationId: purchase-orders_updateItem
      summary: Update a purchase order item
      description: Updates an item on a draft or rejected purchase order. Other
        statuses return `409 po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          description: Purchase order item ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PurchaseOrderItemWrite"
            examples:
              update:
                value:
                  qty: 6
                  rate: 24000
      responses:
        "200":
          description: The updated item.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PurchaseOrderItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: purchase-orders_deleteItem
      summary: Delete a purchase order item
      description: Deletes an item from a draft or rejected purchase order. Other
        statuses return `409 po_invalid_status`.
      tags:
        - Purchase Orders
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          description: Purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          description: Purchase order item ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted. No content.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /search:
    get:
      operationId: search_workspace
      summary: Search the workspace or one project
      tags:
        - Search
      description: Searches the workspace or one project. Results are ranked by
        relevance and include only records available to the token.
      parameters:
        - name: q
          in: query
          required: true
          description: The search query. 1 to 500 characters.
          schema:
            type: string
            minLength: 1
            maxLength: 500
          examples:
            panavision:
              value: Panavision
        - name: types
          in: query
          required: false
          description: Resource types to search. Omit to search every supported type.
          style: form
          explode: false
          schema:
            type: array
            items:
              $ref: "#/components/schemas/SearchKind"
          examples:
            twoKinds:
              value: transactions,documents
        - name: projectId
          in: query
          required: false
          description: Limit results to one project.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
      responses:
        "200":
          description: Ranked search results.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchResponse"
              examples:
                panavision:
                  summary: Workspace search for "Panavision"
                  value:
                    data:
                      - kind: transactions
                        id: txn_8f2a1c9e
                        label: Panavision Camera Package
                        snippet: Invoice 4471, Panavision rental
                        score: 0.62
                      - kind: documents
                        id: doc_4b71e0aa
                        label: Panavision quote.pdf
                        score: 0.41
                    nextCursor: eyJzIjowLjQxLCJrIjoiZG9jdW1lbnRzIiwiaWQiOiJkb2NfNGI3MSJ9
                    searchedTypes:
                      - transactions
                      - documents
                      - budget-lines
                      - purchase-orders
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "402":
          $ref: "#/components/responses/Error402"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions:
    get:
      operationId: transactions_list
      tags:
        - Transactions
      summary: List transactions
      description: Returns transactions you can access. Filters combine with AND. Each
        page contains up to 100 transactions.
      parameters:
        - name: projectId
          in: query
          description: Project ID or slug. Use `none` for unassigned transactions.
          schema:
            type: string
        - name: source
          in: query
          description: Transaction source. Separate multiple values with commas.
          schema:
            $ref: "#/components/schemas/TransactionSource"
        - name: type
          in: query
          description: Transaction type. Separate multiple values with commas.
          schema:
            type: string
        - name: status
          in: query
          description: Filter by status. Separate multiple values with commas.
          schema:
            $ref: "#/components/schemas/TransactionStatus"
        - name: isReversal
          in: query
          description: Set to `true` for refunds and other reversals.
          schema:
            type: boolean
        - name: contactId
          in: query
          description: Assigned contact ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: budgetLineId
          in: query
          description: Budget line ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: purchaseOrderId
          in: query
          description: Linked purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: currency
          in: query
          description: Three-letter currency code. Required with `amountMin` or `amountMax`.
          schema:
            type: string
            minLength: 3
            maxLength: 3
        - name: dateFrom
          in: query
          description: Earliest transaction time, inclusive. Must be on or before `dateTo`.
          schema:
            type: string
            format: date-time
        - name: dateTo
          in: query
          description: Latest transaction time, inclusive.
          schema:
            type: string
            format: date-time
        - name: amountMin
          in: query
          description: Minimum amount, inclusive, in minor currency units. Requires
            `currency`.
          schema:
            type: integer
            format: int64
        - name: amountMax
          in: query
          description: Maximum amount, inclusive, in minor currency units. Requires
            `currency`.
          schema:
            type: integer
            format: int64
        - name: isItemized
          in: query
          description: Set to `true` for itemized transactions or `false` for transactions
            without items.
          schema:
            type: boolean
        - name: merchant
          in: query
          description: Merchant name. Matching is case-insensitive and partial.
          schema:
            type: string
        - name: hasDocuments
          in: query
          description: Set to `true` for transactions with documents or `false` for
            transactions without documents.
          schema:
            type: boolean
        - name: q
          in: query
          description: Search transaction descriptions.
          schema:
            type: string
        - $ref: "#/components/parameters/transactionExpand"
        - $ref: "#/components/parameters/transactionSort"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/withCount"
      responses:
        "200":
          description: A page of transactions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionCollection"
              example:
                data:
                  - id: txn_8f2a1c9e
                    source: plaid
                    sourceId: plx_991
                    type: CreditCard
                    status: posted
                    isReversal: false
                    amount:
                      amount: 152900
                      currency: USD
                    currency: USD
                    timestamp: 2026-05-20T14:03:00.000Z
                    description: B&H Photo - camera rental
                    merchant: B&H Photo
                    contactId: con_4d5e
                    projectId: prj_films
                    budgetLineId: bud_camera
                    isItemized: false
                    purchaseOrderId: null
                    createdAt: 2026-05-20T14:05:00.000Z
                    updatedAt: 2026-05-20T14:05:00.000Z
                nextCursor: eyJ0cyI6MTY4
                statusReachability:
                  manual:
                    - posted
                    - void
                    - projected
                  plaid:
                    - pending
                    - posted
                    - void
                    - needs_review
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: transactions_create
      tags:
        - Transactions
      summary: Create a manual transaction
      description: Creates a manual transaction. Use `projectId` to assign it to a
        project. Requires an `Idempotency-Key`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key with the same body
            returns the first result. Reusing it with a different body returns
            `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionManualCreate"
            example:
              type: Invoice
              amount:
                amount: 50000
                currency: USD
              timestamp: 2026-05-22T00:00:00.000Z
              description: Vendor invoice
              contactId: con_4d5e
              budgetLineId: bud_postprod
      responses:
        "201":
          description: The created transaction.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
              example:
                id: txn_a1b2c3d4
                source: manual
                sourceId: null
                type: Invoice
                status: posted
                isReversal: false
                amount:
                  amount: 50000
                  currency: USD
                currency: USD
                timestamp: 2026-05-22T00:00:00.000Z
                description: Vendor invoice
                contactId: con_4d5e
                projectId: prj_films
                budgetLineId: bud_postprod
                isItemized: false
                createdAt: 2026-05-22T09:00:00.000Z
                updatedAt: 2026-05-22T09:00:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions/stats:
    get:
      operationId: transactions_stats
      tags:
        - Transactions
      summary: Get transaction totals
      description: Returns the number and total amount of matching transactions in one
        currency.
      parameters:
        - name: projectId
          in: query
          description: Project ID or slug. Use `none` for unassigned transactions.
          schema:
            type: string
        - name: source
          in: query
          description: Transaction source. Separate multiple values with commas.
          schema:
            $ref: "#/components/schemas/TransactionSource"
        - name: type
          in: query
          description: Transaction type. Separate multiple values with commas.
          schema:
            type: string
        - name: status
          in: query
          description: Transaction status. Separate multiple values with commas.
          schema:
            $ref: "#/components/schemas/TransactionStatus"
        - name: isReversal
          in: query
          description: Set to `true` for refunds and other reversals.
          schema:
            type: boolean
        - name: contactId
          in: query
          description: Only transactions for this contact.
          schema:
            $ref: "#/components/schemas/Id"
        - name: budgetLineId
          in: query
          description: Only transactions coded to this budget line.
          schema:
            $ref: "#/components/schemas/Id"
        - name: purchaseOrderId
          in: query
          description: Linked purchase order ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: currency
          in: query
          required: true
          description: Three-letter currency code for the total.
          schema:
            type: string
            minLength: 3
            maxLength: 3
        - name: dateFrom
          in: query
          description: Earliest transaction time, inclusive. Must be on or before `dateTo`.
          schema:
            type: string
            format: date-time
        - name: dateTo
          in: query
          description: Latest transaction time, inclusive.
          schema:
            type: string
            format: date-time
        - name: amountMin
          in: query
          description: Minimum amount, inclusive, in minor currency units.
          schema:
            type: integer
            format: int64
        - name: amountMax
          in: query
          description: Maximum amount, inclusive, in minor currency units.
          schema:
            type: integer
            format: int64
        - name: isItemized
          in: query
          description: Set to `true` for itemized transactions or `false` for transactions
            without items.
          schema:
            type: boolean
        - name: merchant
          in: query
          description: Merchant name. Matching is case-insensitive and partial.
          schema:
            type: string
        - name: hasDocuments
          in: query
          description: Set to `true` for transactions with documents or `false` for
            transactions without documents.
          schema:
            type: boolean
        - name: q
          in: query
          description: Search transaction descriptions.
          schema:
            type: string
      responses:
        "200":
          description: Totals for matching transactions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionStats"
              example:
                total: 142
                amount:
                  amount: 9381200
                  currency: USD
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions/bulk:
    post:
      operationId: transactions_createBulk
      tags:
        - Transactions
      summary: Create manual transactions in bulk
      description: Creates up to 500 manual transactions in one request. If any
        transaction fails, none are created. Requires an `Idempotency-Key`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key with the same body
            returns the first result. Reusing it with a different body returns
            `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionBulkCreate"
            example:
              transactions:
                - type: Cash
                  amount:
                    amount: 2500
                    currency: USD
                  timestamp: 2026-05-18T00:00:00.000Z
                  description: Petty cash - craft services
                - type: Check
                  amount:
                    amount: 120000
                    currency: USD
                  timestamp: 2026-05-19T00:00:00.000Z
                  description: Location fee
                  budgetLineId: bud_locations
      responses:
        "201":
          description: The created transactions.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionCollection"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "413":
          $ref: "#/components/responses/Error413"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions/{transactionId}:
    get:
      operationId: transactions_get
      tags:
        - Transactions
      summary: Get a transaction
      description: Returns a transaction you can access. Otherwise returns `404 not_found`.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/transactionExpand"
      responses:
        "200":
          description: The transaction.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
              example:
                id: txn_8f2a1c9e
                source: saturation_credit
                sourceId: scx_771
                type: CreditCard
                status: posted
                isReversal: true
                amount:
                  amount: -4500
                  currency: USD
                currency: USD
                timestamp: 2026-05-21T10:00:00.000Z
                description: Refund - duplicate charge
                merchant: B&H Photo
                sourceLast4: "4242"
                projectId: prj_films
                budgetLineId: bud_camera
                isItemized: false
                createdAt: 2026-05-21T10:02:00.000Z
                updatedAt: 2026-05-21T10:02:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: transactions_update
      tags:
        - Transactions
      summary: Update a transaction
      description: Updates a transaction. Financial fields can be changed only on
        manual transactions.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionPatch"
            example:
              budgetLineId: bud_camera
              notes: Re-coded to camera package
      responses:
        "200":
          description: The updated transaction.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: transactions_delete
      tags:
        - Transactions
      summary: Delete a manual transaction
      description: Deletes a manual transaction. Other transaction sources return `409`.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Transaction deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions/{transactionId}/items:
    get:
      operationId: transactions_listItems
      tags:
        - Transactions
      summary: List transaction items
      description: Returns the items in a transaction.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: The items.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionItemCollection"
              example:
                data:
                  - id: txi_4a1b2c3d
                    lineNumber: "1"
                    description: Camera body - 3 days
                    budgetLineId: bud_camera
                    qty: 3
                    unit: Day
                    rate:
                      amount: 25000
                      currency: USD
                    amount:
                      amount: 75000
                      currency: USD
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: transactions_createItem
      tags:
        - Transactions
      summary: Add a transaction item
      description: Adds an item to a transaction. Adding the first item moves budget
        coding from the transaction to its items. Requires an `Idempotency-Key`.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: Idempotency-Key
          in: header
          required: true
          description: A unique 16-255 character key. Reusing the key with the same body
            returns the first result. Reusing it with a different body returns
            `409 idempotency_conflict`.
          schema:
            type: string
            minLength: 16
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionItemCreate"
            example:
              description: Lens kit - 3 days
              budgetLineId: bud_camera
              qty: 3
              unit: Day
              rate:
                amount: 8000
                currency: USD
              amount:
                amount: 24000
                currency: USD
      responses:
        "201":
          description: The created item.
          headers:
            Idempotency-Replayed:
              $ref: "#/components/headers/IdempotencyReplayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /transactions/{transactionId}/items/{itemId}:
    patch:
      operationId: transactions_updateItem
      tags:
        - Transactions
      summary: Update a transaction item
      description: Updates a transaction item. Read-only fields return `422
        field_read_only`.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          description: Transaction item ID.
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionItemPatch"
            example:
              qty: 4
              amount:
                amount: 32000
                currency: USD
      responses:
        "200":
          description: The updated item.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionItem"
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: transactions_deleteItem
      tags:
        - Transactions
      summary: Delete a transaction item
      description: Deletes a transaction item. Deleting the last item marks the
        transaction as not itemized.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID.
          schema:
            $ref: "#/components/schemas/Id"
        - name: itemId
          in: path
          required: true
          description: Transaction item ID.
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Item deleted.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /webhooks:
    get:
      operationId: webhooks_list
      summary: List webhook subscriptions
      description: Returns webhook subscriptions. Filter by event type or active state.
      tags:
        - Webhook Subscriptions
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - name: order
          in: query
          required: false
          description: Sort direction.
          schema:
            type: string
            enum:
              - asc
              - desc
            default: asc
        - $ref: "#/components/parameters/withCount"
        - name: events
          in: query
          required: false
          description: Only subscriptions that include at least one of these
            comma-separated event types.
          schema:
            type: array
            items:
              $ref: "#/components/schemas/WebhookEvent"
          style: form
          explode: false
        - name: active
          in: query
          required: false
          description: Filter by whether the subscription is currently delivering
            (`isActive`).
          schema:
            type: boolean
      responses:
        "200":
          description: A page of webhook subscriptions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookCollection"
              example:
                data:
                  - id: whk_5c1a9e02
                    url: https://hooks.example.com/saturation
                    events:
                      - transaction.created
                      - budget.changed
                    isActive: true
                    workspaceId: ws_1a2b3c4d
                    createdAt: 2026-05-28T12:00:00.000Z
                    updatedAt: 2026-05-28T12:00:00.000Z
                nextCursor: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    post:
      operationId: webhooks_create
      summary: Create a webhook subscription
      description: Creates a webhook subscription. The URL must use HTTPS and resolve
        to a public address. If `secret` is omitted, the response includes a
        generated secret once.
      tags:
        - Webhook Subscriptions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookCreate"
            example:
              url: https://hooks.example.com/saturation
              events:
                - transaction.created
                - transaction.updated
                - budget.changed
      responses:
        "201":
          description: The created subscription and its signing secret. Store the secret
            before discarding the response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookWithSecret"
              example:
                id: whk_5c1a9e02
                url: https://hooks.example.com/saturation
                events:
                  - transaction.created
                  - transaction.updated
                  - budget.changed
                isActive: true
                workspaceId: ws_1a2b3c4d
                secret: whsec_example
                createdAt: 2026-05-28T12:00:00.000Z
                updatedAt: 2026-05-28T12:00:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
  /webhooks/{webhookId}:
    get:
      operationId: webhooks_get
      summary: Get a webhook subscription
      description: Returns one webhook subscription.
      tags:
        - Webhook Subscriptions
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Webhook subscription identifier (`whk_…`).
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "200":
          description: The webhook subscription.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
              example:
                id: whk_5c1a9e02
                url: https://hooks.example.com/saturation
                events:
                  - transaction.created
                  - budget.changed
                isActive: true
                workspaceId: ws_1a2b3c4d
                createdAt: 2026-05-28T12:00:00.000Z
                updatedAt: 2026-05-28T12:00:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
    patch:
      operationId: webhooks_update
      summary: Update a webhook subscription
      description: Updates the destination, event types, or active state.
      tags:
        - Webhook Subscriptions
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Webhook subscription identifier (`whk_…`).
          schema:
            $ref: "#/components/schemas/Id"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookUpdate"
            example:
              events:
                - transaction.created
                - purchaseOrder.approved
              isActive: false
      responses:
        "200":
          description: The updated webhook subscription.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
              example:
                id: whk_5c1a9e02
                url: https://hooks.example.com/saturation
                events:
                  - transaction.created
                  - purchaseOrder.approved
                isActive: false
                workspaceId: ws_1a2b3c4d
                createdAt: 2026-05-28T12:00:00.000Z
                updatedAt: 2026-05-28T13:30:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "422":
          $ref: "#/components/responses/Error422"
        "429":
          $ref: "#/components/responses/Error429"
    delete:
      operationId: webhooks_delete
      summary: Delete a webhook subscription
      description: Deletes the subscription. Repeating the request returns `204`.
      tags:
        - Webhook Subscriptions
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Webhook subscription identifier (`whk_…`).
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "204":
          description: Deleted. No content.
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
  /webhooks/{webhookId}/test-delivery:
    post:
      operationId: webhooks_sendTestDelivery
      summary: Send a test delivery
      description: Sends a signed test event and records the delivery attempt.
      tags:
        - Webhook Subscriptions
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Webhook subscription identifier (`whk_…`).
          schema:
            $ref: "#/components/schemas/Id"
      responses:
        "202":
          description: The queued test delivery.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDelivery"
              example:
                id: whd_9a02c1e5
                event: ping
                status: pending
                entityKind: ping
                entityId: whk_5c1a9e02
                requestUrl: https://hooks.example.com/saturation
                attempts: 1
                occurredAt: 2026-05-28T14:00:00.000Z
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "409":
          $ref: "#/components/responses/Error409"
        "429":
          $ref: "#/components/responses/Error429"
  /webhooks/{webhookId}/deliveries:
    get:
      operationId: webhooks_listDeliveries
      summary: List recent deliveries
      description: Returns delivery attempts, newest first. Filter by status, event
        type, or time.
      tags:
        - Webhook Subscriptions
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Webhook subscription identifier (`whk_…`).
          schema:
            $ref: "#/components/schemas/Id"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/cursor"
        - name: order
          in: query
          required: false
          description: Sort direction.
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - $ref: "#/components/parameters/withCount"
        - name: status
          in: query
          required: false
          description: Only deliveries with this attempt outcome.
          schema:
            $ref: "#/components/schemas/WebhookDeliveryStatus"
        - name: event
          in: query
          required: false
          description: Only deliveries for this event type.
          schema:
            $ref: "#/components/schemas/WebhookEvent"
        - name: since
          in: query
          required: false
          description: Only deliveries that occurred at or after this ISO-8601 timestamp.
            An end before the start (when paired with sort bounds) returns `400
            invalid_date_range`.
          schema:
            type: string
            format: date-time
      responses:
        "200":
          description: A page of delivery attempts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryCollection"
              example:
                data:
                  - id: whd_9a02c1e5
                    event: transaction.created
                    status: success
                    entityKind: transaction
                    entityId: txn_8f2a1c9e
                    requestUrl: https://hooks.example.com/saturation
                    responseStatus: 200
                    attempts: 1
                    occurredAt: 2026-05-28T14:00:00.000Z
                    deliveredAt: 2026-05-28T14:00:00.420Z
                nextCursor: null
        "400":
          $ref: "#/components/responses/Error400"
        "401":
          $ref: "#/components/responses/Error401"
        "403":
          $ref: "#/components/responses/Error403"
        "404":
          $ref: "#/components/responses/Error404"
        "429":
          $ref: "#/components/responses/Error429"
webhooks:
  saturationEvent:
    post:
      operationId: webhooks_receiveEvent
      summary: Receive a Saturation event
      description: Saturation sends this request to a webhook subscription URL.
      security: []
      parameters:
        - name: X-Saturation-Signature
          in: header
          required: true
          schema:
            type: string
        - name: X-Saturation-Timestamp
          in: header
          required: true
          schema:
            type: string
            format: date-time
        - name: X-Saturation-Delivery-Id
          in: header
          required: true
          schema:
            $ref: "#/components/schemas/Id"
        - name: X-Saturation-Event
          in: header
          required: true
          schema:
            $ref: "#/components/schemas/WebhookDeliveryEvent"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEventPayload"
      responses:
        "200":
          description: Event accepted.
components:
  headers:
    IdempotencyReplayed:
      description: Present when this response was replayed from an earlier request
        with the same `Idempotency-Key`.
      schema:
        type: string
        const: "true"
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Personal API token sent as `Bearer <token>`. Each token belongs to
        one workspace.
  parameters:
    projectId:
      name: projectId
      in: path
      required: true
      description: Project ID or slug.
      schema:
        type: string
    limit:
      name: limit
      in: query
      required: false
      description: Maximum number of items to return on a page. Capped at 100.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 50
    cursor:
      name: cursor
      in: query
      required: false
      description: Cursor from the previous page's `nextCursor`. Use it with the same
        filters and sort.
      schema:
        type: string
    sort:
      name: sort
      in: query
      required: false
      description: Field to sort by. Allowed fields depend on the resource.
      schema:
        type: string
    order:
      name: order
      in: query
      required: false
      description: Sort direction.
      schema:
        type: string
        enum:
          - asc
          - desc
        default: asc
    transactionSort:
      name: sort
      in: query
      required: false
      description: Field to sort the transactions list by. A non-unique field appends
        `,id` as the tiebreaker. Defaults to `timestamp` `desc`.
      schema:
        $ref: "#/components/schemas/TransactionSortField"
    purchaseOrderSort:
      name: sort
      in: query
      required: false
      description: Field to sort the purchase-order list by. A non-unique field
        appends `,id` as the tiebreaker.
      schema:
        $ref: "#/components/schemas/PurchaseOrderSort"
    transactionExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on transactions (depth ≤ 2).
        Unknown or too-deep key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/TransactionExpandKey"
      style: form
      explode: false
    purchaseOrderExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on a purchase order (depth ≤
        2). Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/PurchaseOrderExpand"
      style: form
      explode: false
    contactExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on contacts (depth ≤ 2).
        Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/ContactExpand"
      style: form
      explode: false
    budgetLineExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on budget lines (depth ≤ 2).
        Unknown or too-deep key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/BudgetLineExpand"
      style: form
      explode: false
    libraryExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on a project copy (depth ≤ 2).
        Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/LibraryExpand"
      style: form
      explode: false
    projectIncentiveExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on a project incentive (depth
        ≤ 2). Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/ProjectIncentiveExpand"
      style: form
      explode: false
    ratePackExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on a workspace-source rate
        pack. Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/RatePackExpand"
      style: form
      explode: false
    incentivePackExpand:
      name: expand
      in: query
      required: false
      description: Comma list of related data to inline on a workspace-source
        incentive pack. Unknown key returns `400 expand_invalid`.
      schema:
        type: array
        items:
          $ref: "#/components/schemas/IncentivePackExpand"
      style: form
      explode: false
    withCount:
      name: withCount
      in: query
      required: false
      description: Include the total number of matching items. Defaults to `false`.
      schema:
        type: boolean
        default: false
  responses:
    Error400:
      description: The request is invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error401:
      description: Unauthenticated, `unauthenticated`, `invalid_token`,
        `missing_authorization` or `token_revoked` (expired, malformed, missing
        or revoked credentials).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error402:
      description: This feature is not available on the workspace plan.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error403:
      description: Forbidden. The token does not allow this action.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error404:
      description: Not found or unavailable to the token.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error409:
      description: The request conflicts with the current resource state.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error413:
      description: Payload / result too large, `budget_too_large` or `bulk_too_large`.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error422:
      description: The request names a read-only field or cannot be processed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error423:
      description: The workspace is temporarily locked.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error429:
      description: Rate limited. See `Retry-After` before retrying.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error503:
      description: The service needed to complete this request is unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Error504:
      description: Budget calculation timed out. The request may be retried.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Id:
      type: string
      description: A stable resource ID, such as `prj_…`, `txn_…`, or `doc_…`.
      examples:
        - txn_8f2a1c9e
    PublicResourceRef:
      type: object
      description: A reference to another resource.
      required:
        - type
        - id
      additionalProperties: false
      properties:
        type:
          type: string
          enum:
            - document
            - payment_request
            - payment
            - transaction
            - approval
        id:
          $ref: "#/components/schemas/Id"
    ErrorCode:
      type: string
      description: Error code for programmatic handling.
      enum:
        - unauthenticated
        - invalid_token
        - missing_authorization
        - token_revoked
        - permission_revoked
        - scope_exceeded
        - forbidden
        - feature_not_available
        - upgrade_required
        - capacity_exceeded
        - approval_required
        - resource_locked
        - temporarily_unavailable
        - role_ceiling_exceeded
        - api_access_disabled
        - not_found
        - document_target_not_found
        - validation
        - cursor_invalid
        - expand_invalid
        - invalid_date_range
        - webhook_https_required
        - range_too_large
        - account_path_ambiguous
        - account_code_ambiguous
        - budget_compute_stale
        - idempotency_conflict
        - already_linked
        - status_unreachable_for_source
        - po_invalid_status
        - webhook_url_invalid_ssrf
        - phase_copy_unsupported
        - field_read_only
        - scenario_too_large
        - source_not_postable
        - webhook_url_blocked
        - budget_too_large
        - bulk_too_large
        - rate_limited
        - signing_key_not_configured
        - internal_error
        - budget_compute_timeout
    Error:
      type: object
      description: "The uniform error envelope. Only errors carry `success: false`;
        success responses are the bare resource or a `{ data, nextCursor? }`
        collection."
      required:
        - success
        - code
        - message
        - requestId
      additionalProperties: false
      properties:
        success:
          type: boolean
          const: false
          description: Always `false`. Present only on errors.
        code:
          $ref: "#/components/schemas/ErrorCode"
        message:
          type: string
          description: Human-readable description of the failure.
        requestId:
          type: string
          description: Request ID for support and troubleshooting.
          examples:
            - req_3f9b2a7c
        fieldErrors:
          type: object
          description: Validation messages keyed by input field.
          additionalProperties:
            type: array
            items:
              type: string
        requiredAbility:
          type: string
          description: Permission required for the action, such as `update:Transaction`.
        retryAfter:
          type: integer
          description: Seconds to wait before retrying.
        accessDecision:
          $ref: "#/components/schemas/ProductAccessDecision"
          description: Product-access details when the operation is unavailable.
    ProductAccessDecision:
      type: object
      description: Explains why a product feature is unavailable and how to resolve it.
      required:
        - operationId
        - allowed
        - state
        - primary
        - remediations
        - resolvingPlanId
      additionalProperties: false
      properties:
        operationId:
          type: string
          minLength: 1
        allowed:
          type: boolean
        state:
          type: string
          enum:
            - allowed
            - warning
            - denied
            - indeterminate
        primary:
          type:
            - object
            - "null"
          additionalProperties: false
          required:
            - kind
            - status
            - reason
          properties:
            kind:
              type: string
              enum:
                - principal
                - authority
                - policy
                - rollout
                - provider
                - entitlement
                - quota
            status:
              type: string
              enum:
                - warning
                - denied
                - indeterminate
            reason:
              type: string
              enum:
                - principal_unauthenticated
                - principal_expired
                - principal_suspended
                - resource_unreachable
                - permission_denied
                - resource_locked
                - approval_required
                - safety_restricted
                - rollout_disabled
                - delivery_unavailable
                - provider_unavailable
                - provider_ineligible
                - legal_restricted
                - plan_excluded
                - contract_restricted
                - subscription_restricted
                - quota_warning
                - quota_exhausted
                - quota_unknown
                - quota_reservation_required
                - dependency_unknown
            quotaId:
              type: string
              minLength: 1
            usage:
              type: integer
              minimum: 0
            limit:
              type: integer
              minimum: 0
        remediations:
          type: array
          items:
            type: string
            enum:
              - self_serve_upgrade
              - contact_billing_owner
              - contact_sales
              - buy_capacity
              - cleanup
              - authenticate
              - request_access
              - resolve_policy
              - wait_for_rollout
              - resolve_provider
              - recover_payment
              - reactivate_subscription
              - contact_support
              - renew_link
        currentPlanId:
          type: string
          enum:
            - free
            - pro
            - team
            - enterprise
        resolvingPlanId:
          type:
            - string
            - "null"
          enum:
            - free
            - pro
            - team
            - enterprise
            - null
        correlationId:
          type: string
          minLength: 1
    Money:
      type: object
      description: An amount in integer minor units and its ISO-4217 currency.
      required:
        - amount
        - currency
      additionalProperties: false
      properties:
        amount:
          type: integer
          format: int64
          description: Amount in the currency's smallest unit, such as cents. May be
            negative.
          examples:
            - 152900
        currency:
          type: string
          description: ISO-4217 currency code.
          minLength: 3
          maxLength: 3
          examples:
            - USD
    NextCursor:
      type:
        - string
        - "null"
      description: Cursor for the next page. Pass it as `cursor` with the same filters
        and sort. Null on the last page.
      examples:
        - eyJpZCI6InR4bl84ZjJhMWM5ZSJ9
        - null
    PhaseType:
      type: string
      description: The phase type.
      enum:
        - estimate
        - actual
        - rollup
        - committed
      examples:
        - estimate
    BudgetLineType:
      type: string
      description: The budget line type.
      enum:
        - account
        - line
        - subtotal
        - fringe
        - markup
        - credit
        - banner
    ComputedLineType:
      type: string
      description: The budget line types included in a budget document.
      enum:
        - account
        - line
        - credit
        - fringe
    BudgetLineExpand:
      type: string
      description: A related resource to include with a budget line. Pass multiple
        values as a comma-separated list. The maximum depth is 2.
      enum:
        - phaseTotals
        - phaseData
        - contact
    BudgetLineContactRef:
      type: object
      description: Contact details included with a budget line.
      required:
        - id
        - displayName
        - name
        - company
        - email
        - type
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        displayName:
          type: string
        name:
          type:
            - string
            - "null"
        company:
          type:
            - string
            - "null"
        email:
          type:
            - string
            - "null"
        type:
          type:
            - string
            - "null"
    TagMode:
      type: string
      description: How multiple tag filters are combined. `any` matches at least one
        tag, `all` matches every tag, and `none` excludes matching tags.
      enum:
        - any
        - all
        - none
      default: any
    FringeBreakdownEntry:
      type: object
      description: One fringe included in a phase total.
      required:
        - id
        - name
        - amount
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
          description: The fringe name.
        amount:
          type: integer
          format: int64
          description: The fringe amount in the workspace currency's minor units.
    PhaseValues:
      type: object
      description: Totals for one budget line and phase. Amounts use the workspace
        currency's minor units. `amount` and `combined` are equal.
      required:
        - base
        - overtime
        - fringe
        - fringeBreakdown
        - amount
        - combined
        - currency
      additionalProperties: false
      properties:
        base:
          type: integer
          format: int64
          description: The amount before overtime and fringes, in minor units.
        overtime:
          type: integer
          format: int64
          description: The overtime amount in minor units.
        fringe:
          type: integer
          format: int64
          description: The total fringe amount in minor units.
        fringeBreakdown:
          type: array
          description: The fringes included in `fringe`.
          items:
            $ref: "#/components/schemas/FringeBreakdownEntry"
        amount:
          type: integer
          format: int64
          description: The total amount in minor units.
        combined:
          type: integer
          format: int64
          description: The total after overtime, fringes, and credits. Equal to `amount`.
        currency:
          type: string
          description: The workspace currency as an ISO 4217 code.
          minLength: 3
          maxLength: 3
          examples:
            - USD
      examples:
        - base: 1000000
          overtime: 0
          fringe: 220000
          fringeBreakdown:
            - id: frg_pension
              name: Pension
              amount: 220000
          amount: 1220000
          combined: 1220000
          currency: USD
    BudgetPhase:
      type: object
      description: A phase column in the budget.
      required:
        - id
        - type
        - name
        - sort
        - isHidden
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        type:
          $ref: "#/components/schemas/PhaseType"
        name:
          type: string
          description: The phase name.
        alias:
          type:
            - string
            - "null"
          description: A short name for the phase column.
        color:
          type:
            - string
            - "null"
          description: The phase color.
        sort:
          type: integer
          description: The phase's display order.
        isHidden:
          type: boolean
          description: Whether the phase is hidden.
        displayDecimals:
          type:
            - integer
            - "null"
          minimum: 0
          maximum: 4
          description: Decimal places shown for phase amounts. Null uses the currency
            default.
        baseCurrencyId:
          description: The phase currency. Used by estimate, actual, and rollup phases.
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        actualDateStart:
          type:
            - string
            - "null"
          format: date
        actualDateEnd:
          type:
            - string
            - "null"
          format: date
        actualStatuses:
          type:
            - array
            - "null"
          items:
            type: string
        actualSourceTypes:
          type:
            - array
            - "null"
          description: Sources included in an actual phase. Manual transactions use
            `manual`.
          items:
            type: string
        actualCurrencies:
          type:
            - array
            - "null"
          items:
            type: string
            minLength: 3
            maxLength: 3
        actualContactId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        actualTagIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        actualBudgetLineIds:
          type:
            - array
            - "null"
          items:
            $ref: "#/components/schemas/Id"
        estimateTagIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        overtimeFactors:
          type: array
          items:
            type: string
            enum:
              - qty
              - x
        committedDateStart:
          type:
            - string
            - "null"
          format: date
        committedDateEnd:
          type:
            - string
            - "null"
          format: date
        committedContactId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        committedPhaseIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        committedPoStatuses:
          type: array
          items:
            type: string
            enum:
              - approved
              - paymentRequested
              - paymentRejected
              - paymentProcessing
        rollupFormula:
          type:
            - string
            - "null"
          description: The formula for a rollup phase.
        rollupDisplayMode:
          type:
            - string
            - "null"
          enum:
            - value
            - percent
            - bars
            - margin
            - null
      examples:
        - id: phs_estimate
          type: estimate
          name: Estimate
          alias: EST
          color: blue
          sort: 0
          isHidden: false
    BudgetLine:
      type: object
      description: A budget line. Related data appears when requested with `expand`.
      required:
        - id
        - type
        - description
        - parentId
        - sort
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        accountId:
          type:
            - string
            - "null"
          description: The account number. It does not need to be unique.
          examples:
            - "1100"
        path:
          type:
            - string
            - "null"
          description: The account path, such as `1100/1110`.
          examples:
            - 1100/1110
        type:
          $ref: "#/components/schemas/BudgetLineType"
        description:
          type: string
          description: The line description.
        parentId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        depth:
          type: integer
          description: The line's depth in the account tree. Root accounts have depth 0.
        sort:
          type: integer
          description: The display order among lines with the same parent.
        contactId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        lineColor:
          type:
            - string
            - "null"
          description: The line color.
        emoji:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
          description: A plain-text note on the line.
        tagIds:
          type: array
          description: The IDs of tags on this line.
          items:
            $ref: "#/components/schemas/Id"
        subtotalSumAllAbove:
          type: boolean
          description: For a `subtotal` line, whether to include every preceding line.
        subtotalIsBold:
          type: boolean
        markupAccountFilter:
          type:
            - string
            - "null"
          description: For a `markup` line, the accounts included in the markup.
        contact:
          description: The contact. Included with `expand=contact`.
          oneOf:
            - $ref: "#/components/schemas/BudgetLineContactRef"
            - type: "null"
        phaseTotals:
          type: object
          description: Totals keyed by phase ID. Included with `expand=phaseTotals`.
          additionalProperties:
            $ref: "#/components/schemas/PhaseValues"
        phaseData:
          type: object
          description: Editable phase data keyed by phase ID. Included with
            `expand=phaseData`.
          additionalProperties:
            $ref: "#/components/schemas/BudgetDocumentLinePhaseData"
      examples:
        - id: lin_7c1a2f
          accountId: "1100"
          path: "1100"
          type: account
          description: Camera
          parentId: lin_root
          depth: 0
          sort: 0
          contactId: null
          tagIds:
            - tag_vfx
          sourceId: null
    BudgetLineCreate:
      type: object
      description: Details for a new budget line.
      required:
        - description
      additionalProperties: false
      properties:
        description:
          type: string
          maxLength: 255
          description: The line description.
        type:
          $ref: "#/components/schemas/BudgetLineType"
        accountId:
          type: string
          description: The account number. It does not need to be unique.
        parentId:
          $ref: "#/components/schemas/Id"
        contactId:
          $ref: "#/components/schemas/Id"
        lineColor:
          type: string
        emoji:
          type: string
        notes:
          type: string
        tagIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        subtotalSumAllAbove:
          type: boolean
        subtotalIsBold:
          type: boolean
        markupAccountFilter:
          type: string
        phaseData:
          type: object
          description: Optional initial editable phase data keyed by phase id.
          additionalProperties:
            $ref: "#/components/schemas/BudgetLinePhaseDataWrite"
      examples:
        - description: Camera Package
          type: line
          accountId: "1110"
          parentId: lin_7c1a2f
          contactId: con_panavision
          tagIds:
            - tag_vfx
          phaseData:
            phs_estimate:
              rate: 25000
              quantity: 4
              multiplier: 1
    BudgetLineUpdate:
      type: object
      description: Changes to a budget line.
      additionalProperties: false
      minProperties: 1
      properties:
        description:
          type: string
          maxLength: 255
        type:
          $ref: "#/components/schemas/BudgetLineType"
        accountId:
          type: string
        parentId:
          $ref: "#/components/schemas/Id"
        contactId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        lineColor:
          type:
            - string
            - "null"
        emoji:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
        tagIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        subtotalSumAllAbove:
          type: boolean
        subtotalIsBold:
          type: boolean
        markupAccountFilter:
          type:
            - string
            - "null"
        phaseData:
          type: object
          description: Upsert editable phase data keyed by phase id. Omitted fields are
            left unchanged.
          additionalProperties:
            $ref: "#/components/schemas/BudgetLinePhaseDataWrite"
      examples:
        - description: Camera Package (A-cam)
          notes: Confirmed with vendor 5/12
    BudgetDocumentPhaseDataValue:
      description: A phase value. Formulas and variable references remain strings. A
        missing value is null.
      type:
        - number
        - string
        - "null"
    BudgetDocumentOvertime:
      type:
        - object
        - "null"
      additionalProperties: false
      properties:
        mode:
          type:
            - string
            - "null"
        flatAmount:
          type:
            - number
            - "null"
        hours:
          type:
            - number
            - "null"
        baseHours:
          type:
            - number
            - "null"
        multipliers:
          description: Overtime multipliers.
        detail:
          description: Overtime details.
    BudgetDocumentLinePhaseData:
      type: object
      description: Editable data for one budget line and phase.
      required:
        - rate
        - quantity
        - multiplier
        - qtyAutoDerived
        - unit
        - customUnitId
        - unitLabel
        - startDate
        - endDate
        - fringeIds
        - fringeGroupIds
        - currencyId
        - overtime
      additionalProperties: false
      properties:
        rate:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        quantity:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        multiplier:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        qtyAutoDerived:
          type: boolean
        unit:
          type:
            - string
            - "null"
        customUnitId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        unitLabel:
          type:
            - string
            - "null"
        startDate:
          type:
            - string
            - "null"
        endDate:
          type:
            - string
            - "null"
        fringeIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        fringeGroupIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        currencyId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        overtime:
          $ref: "#/components/schemas/BudgetDocumentOvertime"
    BudgetLinePhaseDataWrite:
      type: object
      description: Changes to one budget line and phase. Omitted fields remain unchanged.
      additionalProperties: false
      properties:
        rate:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        quantity:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        multiplier:
          $ref: "#/components/schemas/BudgetDocumentPhaseDataValue"
        qtyAutoDerived:
          type:
            - boolean
            - "null"
        unit:
          type:
            - string
            - "null"
        customUnitId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        startDate:
          type:
            - string
            - "null"
        endDate:
          type:
            - string
            - "null"
        fringeIds:
          oneOf:
            - type: array
              items:
                $ref: "#/components/schemas/Id"
            - type: "null"
        fringeGroupIds:
          oneOf:
            - type: array
              items:
                $ref: "#/components/schemas/Id"
            - type: "null"
        currencyId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        overtime:
          $ref: "#/components/schemas/BudgetDocumentOvertime"
    BudgetLinePhaseDataUpsert:
      allOf:
        - $ref: "#/components/schemas/BudgetLinePhaseDataWrite"
    BudgetLinePhaseDataUpsertResponse:
      type: object
      required:
        - lineId
        - phaseId
        - phaseData
      additionalProperties: false
      properties:
        lineId:
          $ref: "#/components/schemas/Id"
        phaseId:
          $ref: "#/components/schemas/Id"
        phaseData:
          $ref: "#/components/schemas/BudgetDocumentLinePhaseData"
    BudgetLineBulkCreate:
      type: object
      required:
        - lines
      additionalProperties: false
      properties:
        lines:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: "#/components/schemas/BudgetLineCreate"
    BudgetLineBulkCreateResponse:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BudgetLine"
    BudgetLinePhaseDataBulkUpsert:
      type: object
      required:
        - items
      additionalProperties: false
      properties:
        items:
          type: array
          minItems: 1
          maxItems: 500
          items:
            type: object
            required:
              - lineId
              - phaseId
              - phaseData
            additionalProperties: false
            properties:
              lineId:
                $ref: "#/components/schemas/Id"
              phaseId:
                $ref: "#/components/schemas/Id"
              phaseData:
                $ref: "#/components/schemas/BudgetLinePhaseDataWrite"
    BudgetLinePhaseDataBulkUpsertResponse:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BudgetLinePhaseDataUpsertResponse"
    BudgetDocumentPhaseValues:
      type: object
      description: Totals for one phase. Amounts use the workspace currency's minor units.
      required:
        - base
        - overtime
        - fringe
        - fringeBreakdown
        - amount
        - currency
      additionalProperties: false
      properties:
        base:
          type: integer
          format: int64
        overtime:
          type: integer
          format: int64
        fringe:
          type: integer
          format: int64
        fringeBreakdown:
          type: array
          items:
            $ref: "#/components/schemas/FringeBreakdownEntry"
        amount:
          type: integer
          format: int64
        currency:
          type: string
          minLength: 3
          maxLength: 3
    BudgetDocumentSelection:
      type: object
      description: The filters applied to the budget document.
      additionalProperties: false
      properties:
        path:
          type: string
        accountId:
          type: string
        phase:
          type: string
    BudgetDocumentLine:
      type: object
      description: A budget line with totals and editable phase data.
      required:
        - id
        - description
        - parentId
        - depth
        - type
        - values
        - phaseData
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        accountId:
          type:
            - string
            - "null"
        description:
          type: string
        parentId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        path:
          type:
            - string
            - "null"
        depth:
          type: integer
        type:
          $ref: "#/components/schemas/ComputedLineType"
        values:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/BudgetDocumentPhaseValues"
        phaseData:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/BudgetDocumentLinePhaseData"
    BudgetDocument:
      type: object
      description: The budget's visible phases, totals, lines, and editable phase data.
      required:
        - id
        - computedAt
        - selection
        - phases
        - totals
        - lines
      additionalProperties: false
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The budget ID.
        computedAt:
          type: string
          format: date-time
        selection:
          $ref: "#/components/schemas/BudgetDocumentSelection"
        phases:
          type: array
          items:
            $ref: "#/components/schemas/BudgetPhase"
        totals:
          type: object
          description: Totals keyed by visible phase ID.
          additionalProperties:
            $ref: "#/components/schemas/BudgetDocumentPhaseValues"
        lines:
          type: array
          description: Budget lines in flat order. Use `parentId` to build the tree.
          items:
            $ref: "#/components/schemas/BudgetDocumentLine"
    BudgetTotals:
      type: object
      description: Budget totals at `computedAt`, optionally filtered by phase or account.
      required:
        - computedAt
        - totals
      additionalProperties: false
      properties:
        computedAt:
          type: string
          format: date-time
        totals:
          type: object
          description: Totals keyed by phase ID.
          additionalProperties:
            $ref: "#/components/schemas/PhaseValues"
        filter:
          type: object
          description: The filters applied to these totals.
          additionalProperties: false
          properties:
            phase:
              type: string
            accountId:
              type: string
            path:
              type: string
      examples:
        - computedAt: 2026-05-28T18:04:11Z
          totals:
            phs_estimate:
              base: 1000000
              overtime: 0
              fringe: 220000
              fringeBreakdown: []
              amount: 1220000
              combined: 1220000
              currency: USD
    DocumentTargetKind:
      type: string
      description: The type of entity linked to a document. A document can have one
        link of each kind.
      enum:
        - project
        - contact
        - transaction
        - payment
        - purchaseOrder
        - budgetLine
        - paymentRequest
      examples:
        - transaction
    DocumentWritableTargetKind:
      type: string
      description: A target callers can link directly. Payment-request links are
        managed by approvals.
      enum:
        - project
        - contact
        - transaction
        - payment
        - purchaseOrder
        - budgetLine
    DocumentStatus:
      type: string
      description: The document's extraction status. `ready` means extracted data is
        available.
      enum:
        - pending
        - processing
        - ready
        - failed
      examples:
        - ready
    DocumentCoarseType:
      type: string
      description: The document category found during extraction.
      enum:
        - financial
        - tax
        - legal
        - insurance
        - production
        - other
      examples:
        - financial
    DocumentTargetRef:
      type: object
      description: An entity linked to a document.
      required:
        - kind
        - id
      additionalProperties: false
      properties:
        kind:
          $ref: "#/components/schemas/DocumentTargetKind"
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The linked entity's ID. Its prefix must match `kind`.
        phaseId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: The phase for a budget-line link.
      examples:
        - kind: transaction
          id: txn_8f2a1c9e
    Document:
      type: object
      description: An uploaded document and its links.
      required:
        - id
        - name
        - mimeType
        - size
        - status
        - workspaceId
        - links
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The document ID.
        name:
          type: string
          description: The document's display name.
        mimeType:
          type: string
          description: The file's MIME type.
          examples:
            - application/pdf
        size:
          type: integer
          format: int64
          description: The file size in bytes.
          examples:
            - 184320
        status:
          $ref: "#/components/schemas/DocumentStatus"
        workspaceId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The workspace ID.
        pageCount:
          type:
            - integer
            - "null"
          description: The number of pages, or null until extraction finishes.
        classification:
          type:
            - string
            - "null"
          description: The document classification, such as `invoice` or `receipt`.
        coarseType:
          description: The document category, or null until classification finishes.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/DocumentCoarseType"
            - type: "null"
        hasSensitiveInfo:
          type:
            - boolean
            - "null"
          description: Whether the document may contain sensitive information.
        description:
          type:
            - string
            - "null"
          description: The document description.
        source:
          type:
            - string
            - "null"
          description: How the document was added, such as `api`, `agent`, or `upload`.
        folderId:
          description: The folder ID, or null for the workspace root.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        projectId:
          description: The project ID, or null for a workspace document.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        contentHash:
          type:
            - string
            - "null"
          description: A hash of the file contents.
        links:
          type: array
          description: The entities linked to this document.
          items:
            $ref: "#/components/schemas/DocumentTargetRef"
        createdAt:
          type: string
          format: date-time
          description: When the document was created.
        updatedAt:
          type: string
          format: date-time
          description: When the document was last updated.
      examples:
        - id: doc_4b1f0a7c
          name: vendor-invoice-0425.pdf
          mimeType: application/pdf
          size: 184320
          status: ready
          workspaceId: ws_71aa
          pageCount: 2
          classification: invoice
          coarseType: financial
          folderId: fld_9c2d
          projectId: prj_71aa
          links:
            - kind: transaction
              id: txn_8f2a1c9e
          createdAt: 2026-05-28T14:03:11Z
          updatedAt: 2026-05-28T14:03:40Z
    DocumentExtractedField:
      type: object
      description: A field extracted from a document.
      required:
        - value
      additionalProperties: false
      properties:
        value:
          type:
            - string
            - "null"
          description: The extracted value. Money uses decimal strings and dates use ISO
            8601. Null means no value was found.
        confidence:
          type:
            - number
            - "null"
          description: Confidence from 0 to 1, or null when unavailable.
          minimum: 0
          maximum: 1
      examples:
        - value: B&H Photo
          confidence: 0.95
    DocumentExtractedLineItem:
      type: object
      description: A line item extracted from a document.
      additionalProperties: false
      properties:
        description:
          type:
            - string
            - "null"
        amount:
          description: The extracted line amount.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Money"
            - type: "null"
        confidence:
          type:
            - number
            - "null"
          description: Confidence from 0 to 1, or null when unavailable.
          minimum: 0
          maximum: 1
    DocumentExtraction:
      type: object
      description: Data extracted from a document. Available when the document status
        is `ready`.
      required:
        - documentId
        - status
        - fields
      additionalProperties: false
      properties:
        documentId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The document ID.
        status:
          $ref: "#/components/schemas/DocumentStatus"
        classification:
          type:
            - string
            - "null"
          description: The document classification, such as `invoice` or `receipt`.
        coarseType:
          description: The document category.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/DocumentCoarseType"
            - type: "null"
        extractedAt:
          type:
            - string
            - "null"
          format: date-time
          description: When extraction finished, or null while unavailable.
        fields:
          type: object
          description: Extracted values and confidence scores keyed by field name. Keys
            vary by classification.
          additionalProperties:
            $ref: "#/components/schemas/DocumentExtractedField"
        lineItems:
          type: array
          description: Extracted line items, when available.
          items:
            $ref: "#/components/schemas/DocumentExtractedLineItem"
      examples:
        - documentId: doc_4b1f0a7c
          status: ready
          classification: invoice
          coarseType: financial
          extractedAt: 2026-05-28T14:03:40Z
          fields:
            invoiceNumber:
              value: "4471"
              confidence: 0.98
            total:
              value: "1529.00"
              confidence: 0.91
          lineItems:
            - description: Camera body rental - 3 days
              amount:
                amount: 75000
                currency: USD
              confidence: 0.86
    DocumentCollection:
      type: object
      description: A page of documents.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Document"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total results when `withCount=true`.
        truncated:
          type: boolean
          description: Whether the page ended before `limit` because some results were
            unavailable.
    DocumentLinkRequest:
      type: object
      description: Links a document to an entity.
      required:
        - targetId
      additionalProperties: false
      properties:
        targetId:
          $ref: "#/components/schemas/Id"
        phaseId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: The phase for a budget-line link.
        replace:
          type: boolean
          default: false
          description: Replace the existing link of this kind.
    DocumentCreateRequest:
      type: object
      description: A multipart upload with a file and optional JSON-serialized metadata.
      required:
        - file
      additionalProperties: false
      properties:
        file:
          type: string
          format: binary
          description: The file to upload.
        metadata:
          type: string
          description: JSON-serialized `DocumentCreateMetadata`.
          examples:
            - '{"name":"vendor-invoice-0425.pdf","links":{"kind":"transaction","id":"txn_8f2a1c9e"}}'
    DocumentUpdateRequest:
      type: object
      description: Changes a document's name, description, or folder.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          description: The new display name.
        description:
          type:
            - string
            - "null"
          description: The new description, or null to clear it.
        folderId:
          description: The new folder ID, or null for the workspace root.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
      examples:
        - name: vendor-invoice-april.pdf
          folderId: fld_9c2d
    PackVisibility:
      type: string
      description: Who can access the pack. Public packs are available to every
        workspace; private packs belong to one workspace.
      enum:
        - public
        - private
        - shared
    TagColor:
      type:
        - string
        - "null"
      description: Display color for a tag, or `null` for the default color.
      enum:
        - slate
        - gray
        - zinc
        - red
        - orange
        - amber
        - yellow
        - lime
        - green
        - emerald
        - teal
        - cyan
        - sky
        - blue
        - indigo
        - violet
        - purple
        - pink
        - rose
        - null
    SourceType:
      type: string
      description: Where the project Library item came from.
      enum:
        - workspace
        - saturation
    SourceTombstone:
      type: object
      description: Identifies a deleted Library source when `expand=source` is requested.
      required:
        - id
        - deleted
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        deleted:
          type: boolean
          const: true
    LibraryExpand:
      type: string
      description: Related data to include with a project Library item.
      enum:
        - source
    ProjectIncentiveExpand:
      type: string
      description: Related data to include with a project incentive.
      enum:
        - source
    RatePackExpand:
      type: string
      description: Related data to include with a rate pack.
      enum:
        - items
    IncentivePackExpand:
      type: string
      description: Related data to include with an incentive pack.
      enum:
        - programs
    RatePackVersionRef:
      type: object
      description: Current rate pack version.
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        effectiveDate:
          type:
            - string
            - "null"
          format: date
        itemCount:
          type: integer
          description: Count of non-blank items in the latest version.
    RatePack:
      type: object
      description: A public or workspace-owned rate pack.
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        slug:
          type: string
        name:
          type: string
        description:
          type:
            - string
            - "null"
        publisher:
          type:
            - string
            - "null"
        category:
          type: string
        tags:
          type: array
          items:
            type: string
        visibility:
          $ref: "#/components/schemas/PackVisibility"
        isOwned:
          type: boolean
          description: Whether the workspace owns the pack.
        deprecated:
          type: boolean
          description: Whether the pack is deprecated. Deprecated packs cannot be newly
            enabled or added.
        enabled:
          type: boolean
          description: Whether the pack is enabled for the workspace.
        enabledAt:
          type:
            - string
            - "null"
          format: date-time
        enabledBy:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        latestVersion:
          $ref: "#/components/schemas/RatePackVersionRef"
        items:
          type: array
          description: Accessible rate pack items. Included with `expand=items`.
          items:
            $ref: "#/components/schemas/RatePackItem"
      required:
        - id
        - slug
        - name
        - category
        - visibility
        - isOwned
        - deprecated
        - enabled
    RatePackCreate:
      type: object
      description: Fields accepted when creating a workspace rate pack. The new pack
        is enabled automatically.
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
        description:
          type: string
        category:
          type: string
          default: custom
        tags:
          type: array
          items:
            type: string
    RatePackUpdate:
      type: object
      description: Fields accepted when updating a workspace-owned rate pack.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        description:
          type:
            - string
            - "null"
        category:
          type: string
        tags:
          type: array
          items:
            type: string
    RatePackItem:
      type: object
      description: A rate in the current pack version.
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        title:
          type: string
        description:
          type:
            - string
            - "null"
        rate:
          $ref: "#/components/schemas/Money"
        unit:
          type: string
        quantity:
          type:
            - number
            - "null"
        multiplier:
          type:
            - number
            - "null"
        group:
          type:
            - string
            - "null"
        agreement:
          type:
            - string
            - "null"
        local:
          type:
            - string
            - "null"
        effectiveDate:
          type:
            - string
            - "null"
          format: date
        labels:
          type: array
          items:
            type: string
        displayTags:
          type: array
          items:
            type: string
        version:
          $ref: "#/components/schemas/RatePackVersionRef"
      required:
        - id
        - title
        - rate
        - unit
    RatePackItemCreate:
      type: object
      description: Fields accepted when adding a rate pack item.
      additionalProperties: false
      required:
        - title
        - rate
        - unit
      properties:
        title:
          type: string
          minLength: 1
        rate:
          $ref: "#/components/schemas/Money"
        unit:
          type: string
        description:
          type: string
        quantity:
          type: number
        multiplier:
          type: number
        group:
          type: string
        agreement:
          type: string
        local:
          type: string
        effectiveDate:
          type: string
          format: date
        labels:
          type: array
          items:
            type: string
        displayTags:
          type: array
          items:
            type: string
    RatePackItemUpdate:
      type: object
      description: Fields accepted when updating a rate pack item. Only supplied
        fields change.
      additionalProperties: false
      minProperties: 1
      properties:
        title:
          type: string
          minLength: 1
        rate:
          $ref: "#/components/schemas/Money"
        unit:
          type: string
        description:
          type:
            - string
            - "null"
        quantity:
          type:
            - number
            - "null"
        multiplier:
          type:
            - number
            - "null"
        group:
          type:
            - string
            - "null"
        agreement:
          type:
            - string
            - "null"
        local:
          type:
            - string
            - "null"
        effectiveDate:
          type:
            - string
            - "null"
          format: date
        labels:
          type: array
          items:
            type: string
    IncentivePack:
      type: object
      description: A collection of incentive programs available to the workspace.
      additionalProperties: false
      required:
        - id
        - slug
        - name
        - jurisdiction
        - visibility
        - isOwned
        - deprecated
        - enabled
      properties:
        id:
          $ref: "#/components/schemas/Id"
        slug:
          type: string
        name:
          type: string
        description:
          type:
            - string
            - "null"
        category:
          type:
            - string
            - "null"
        jurisdiction:
          type: string
          description: Country, state, or province where the incentive applies.
        visibility:
          $ref: "#/components/schemas/PackVisibility"
        isOwned:
          type: boolean
        deprecated:
          type: boolean
        enabled:
          type: boolean
        enabledAt:
          type:
            - string
            - "null"
          format: date-time
        programs:
          type: array
          description: Incentive programs. Included with `expand=programs`.
          items:
            $ref: "#/components/schemas/IncentiveProgram"
    IncentiveProgramVersion:
      type: object
      description: The current published version of an incentive program.
      additionalProperties: false
      required:
        - id
        - effectiveDate
      properties:
        id:
          $ref: "#/components/schemas/Id"
        effectiveDate:
          type: string
          format: date
    IncentiveProgram:
      type: object
      description: An incentive program that can be added to a project when published.
      additionalProperties: false
      required:
        - id
        - name
        - incentiveType
        - incentiveStructure
        - rate
        - discountPercent
        - status
        - currentVersion
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        description:
          type:
            - string
            - "null"
        jurisdiction:
          type:
            - string
            - "null"
        incentiveType:
          type: string
          description: Type of incentive.
          enum:
            - tax_credit
            - rebate
            - grant
        incentiveStructure:
          type: string
          description: How the incentive is paid or transferred.
          enum:
            - tax_credit_refundable
            - tax_credit_transferable
            - tax_credit_nonrefundable
            - cash_rebate
            - grant
        rate:
          type: number
          minimum: 0
          maximum: 100
          description: Headline rate as a percentage. For example, `30` means 30%.
        discountPercent:
          type: number
          minimum: 0
          maximum: 100
          description: Fee deducted from the incentive, as a percentage.
        status:
          type: string
          enum:
            - published
            - blocked
            - deprecated
        currentVersion:
          description: Current published version, or `null` when none is available.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/IncentiveProgramVersion"
            - type: "null"
    ProjectIncentive:
      type: object
      description: An incentive added to a project.
      additionalProperties: false
      required:
        - id
        - name
        - sourceType
        - isApplied
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        jurisdiction:
          type:
            - string
            - "null"
        incentiveType:
          type:
            - string
            - "null"
        sourceType:
          $ref: "#/components/schemas/SourceType"
        sourceId:
          description: Workspace Library source ID, when applicable.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        sourceIncentiveVersionId:
          description: Incentive version used to create this project incentive.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        isApplied:
          type: boolean
          description: Whether the incentive is currently applied to the project's budget.
        accountNumber:
          type:
            - string
            - "null"
          description: Budget account number for the incentive.
        rate:
          type:
            - number
            - "null"
          description: Credit rate as a percentage. For example, `30` means 30%.
        appliedCreditCap:
          type:
            - integer
            - "null"
          description: Maximum credit in minor currency units, or `null` for no limit.
        discountPercent:
          type:
            - number
            - "null"
          description: Broker fee deducted from the credit, as a percentage.
        tierOverrideKey:
          type:
            - string
            - "null"
          description: Selected incentive tier, or `null` to choose the tier from
            qualified spend.
        source:
          description: Incentive program or deleted source. Included with `expand=source`.
          oneOf:
            - $ref: "#/components/schemas/IncentiveProgram"
            - $ref: "#/components/schemas/SourceTombstone"
    ProjectIncentiveAdd:
      type: object
      description: Selects the published incentive program to add to a project.
      additionalProperties: false
      required:
        - programId
      properties:
        programId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The incentive program to add.
        versionId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Published version to add. Defaults to the current published version.
    ProjectIncentiveUpdate:
      type: object
      description: Fields accepted when updating a project incentive. Money uses minor
        currency units; `rate` and `discountPercent` use percentages.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        isApplied:
          type: boolean
        accountNumber:
          type: string
        incentiveType:
          type: string
          enum:
            - tax_credit
            - rebate
            - grant
        jurisdiction:
          type: string
        rate:
          type: number
          minimum: 0
          maximum: 100
        appliedCreditCap:
          type:
            - integer
            - "null"
          minimum: 0
          multipleOf: 100
        discountPercent:
          type: number
          minimum: 0
          maximum: 100
        tierOverrideKey:
          type:
            - string
            - "null"
    Fringe:
      type: object
      description: A fringe in the workspace Library.
      additionalProperties: false
      required:
        - id
        - name
        - description
        - calculationType
        - fringeGroupIds
        - color
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        description:
          type:
            - string
            - "null"
        calculationType:
          type: string
          enum:
            - percent
            - flat
            - total
        rate:
          type:
            - number
            - "null"
          description: Percentage for percent fringes, or the amount for flat and total
            fringes. For example, `7.65` means 7.65%.
        cutoff:
          type:
            - number
            - "null"
        fringeGroupIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        color:
          type:
            - string
            - "null"
    FringeWrite:
      type: object
      description: Fields accepted when creating or updating a workspace fringe.
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
        description:
          type:
            - string
            - "null"
        calculationType:
          type: string
          enum:
            - percent
            - flat
            - total
        rate:
          type:
            - number
            - "null"
        cutoff:
          type:
            - number
            - "null"
        fringeGroupIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        color:
          type:
            - string
            - "null"
    ProjectFringe:
      type: object
      description: A fringe added to a project from the workspace Library.
      additionalProperties: false
      required:
        - id
        - name
        - description
        - calculationType
        - fringeGroupIds
        - color
        - sourceType
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        description:
          type:
            - string
            - "null"
        calculationType:
          type: string
          enum:
            - percent
            - flat
            - total
        rate:
          type:
            - number
            - "null"
        cutoff:
          type:
            - number
            - "null"
        fringeGroupIds:
          type: array
          items:
            $ref: "#/components/schemas/Id"
        color:
          type:
            - string
            - "null"
        sourceType:
          $ref: "#/components/schemas/SourceType"
        sourceId:
          description: Workspace fringe used to create this project fringe.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        source:
          description: Workspace fringe or deleted source. Included with `expand=source`.
          oneOf:
            - $ref: "#/components/schemas/Fringe"
            - $ref: "#/components/schemas/SourceTombstone"
    Global:
      type: object
      description: A global in the workspace Library.
      additionalProperties: false
      required:
        - id
        - symbol
        - description
        - formula
      properties:
        id:
          $ref: "#/components/schemas/Id"
        symbol:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        formula:
          type:
            - string
            - "null"
        unit:
          type:
            - string
            - "null"
        customUnitId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        phaseOverrides:
          type:
            - object
            - "null"
          additionalProperties:
            type: string
    GlobalWrite:
      type: object
      description: Fields accepted when creating or updating a workspace global.
      additionalProperties: false
      properties:
        symbol:
          type:
            - string
            - "null"
          minLength: 1
        description:
          type:
            - string
            - "null"
        formula:
          type:
            - string
            - "null"
        unit:
          type:
            - string
            - "null"
        customUnitId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
    ProjectGlobal:
      type: object
      description: A global added to a project from the workspace Library.
      additionalProperties: false
      required:
        - id
        - symbol
        - description
        - formula
        - sourceType
      properties:
        id:
          $ref: "#/components/schemas/Id"
        symbol:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        formula:
          type:
            - string
            - "null"
        unit:
          type:
            - string
            - "null"
        customUnitId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        phaseOverrides:
          type:
            - object
            - "null"
          additionalProperties:
            type: string
        sourceType:
          $ref: "#/components/schemas/SourceType"
        sourceId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        source:
          oneOf:
            - $ref: "#/components/schemas/Global"
            - $ref: "#/components/schemas/SourceTombstone"
    Currency:
      type: object
      description: A currency and exchange rate in the workspace Library.
      additionalProperties: false
      required:
        - id
        - code
      properties:
        id:
          $ref: "#/components/schemas/Id"
        code:
          type: string
          description: ISO 4217 currency code.
          minLength: 3
          maxLength: 3
        name:
          type:
            - string
            - "null"
        symbol:
          type:
            - string
            - "null"
        rateToUSD:
          type:
            - number
            - "null"
          description: USD value of one unit of this currency.
    CurrencyWrite:
      type: object
      description: Fields accepted when creating or updating a workspace currency.
      additionalProperties: false
      properties:
        code:
          type: string
          minLength: 3
          maxLength: 3
        name:
          type:
            - string
            - "null"
        symbol:
          type:
            - string
            - "null"
        rateToUSD:
          type:
            - number
            - "null"
          description: USD value of one unit of this currency. For example, use `1.17` for
            EUR when one EUR equals 1.17 USD.
    ProjectCurrency:
      type: object
      description: A currency added to a project from the workspace Library.
      additionalProperties: false
      required:
        - id
        - code
        - sourceType
      properties:
        id:
          $ref: "#/components/schemas/Id"
        code:
          type: string
          minLength: 3
          maxLength: 3
        name:
          type:
            - string
            - "null"
        symbol:
          type:
            - string
            - "null"
        rateToUSD:
          type:
            - number
            - "null"
          description: USD value of one unit of this currency.
        sourceType:
          $ref: "#/components/schemas/SourceType"
        sourceId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        source:
          oneOf:
            - $ref: "#/components/schemas/Currency"
            - $ref: "#/components/schemas/SourceTombstone"
    FringeGroup:
      type: object
      description: A Fringe Group in the workspace Library.
      additionalProperties: false
      required:
        - id
        - name
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        color:
          $ref: "#/components/schemas/TagColor"
    FringeGroupWrite:
      type: object
      description: Fields accepted when creating or updating a workspace Fringe Group.
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
        color:
          $ref: "#/components/schemas/TagColor"
    ProjectFringeGroup:
      type: object
      description: A Fringe Group added to a project from the workspace Library.
      additionalProperties: false
      required:
        - id
        - name
        - sourceType
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        color:
          $ref: "#/components/schemas/TagColor"
        sourceType:
          $ref: "#/components/schemas/SourceType"
        sourceId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        source:
          oneOf:
            - $ref: "#/components/schemas/FringeGroup"
            - $ref: "#/components/schemas/SourceTombstone"
    Tag:
      type: object
      description: A tag in the workspace Library.
      additionalProperties: false
      required:
        - id
        - name
        - createdAt
        - updatedAt
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        color:
          $ref: "#/components/schemas/TagColor"
        description:
          type:
            - string
            - "null"
        eligibilityKey:
          type:
            - string
            - "null"
          description: Key used to match the tag to an eligibility rule.
        sort:
          type:
            - number
            - "null"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    TagCreate:
      type: object
      description: Fields accepted when creating a workspace tag.
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
        color:
          $ref: "#/components/schemas/TagColor"
        description:
          type: string
        eligibilityKey:
          type: string
    TagUpdate:
      type: object
      description: Fields accepted when updating a workspace tag. Only supplied fields
        change.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        color:
          $ref: "#/components/schemas/TagColor"
        description:
          type:
            - string
            - "null"
        eligibilityKey:
          type:
            - string
            - "null"
    Unit:
      type: object
      description: A unit in the Library. `isCustom` identifies workspace units;
        built-in units are read-only.
      additionalProperties: false
      required:
        - id
        - label
        - pluralLabel
        - category
        - hoursPerUnit
        - color
        - isCustom
      properties:
        id:
          type: string
          description: Unit ID.
        label:
          type: string
        pluralLabel:
          type:
            - string
            - "null"
        category:
          type: string
          enum:
            - time
            - quantity
            - flat
        hoursPerUnit:
          type:
            - number
            - "null"
          minimum: 0
        color:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        isCustom:
          type: boolean
        createdAt:
          type: string
          format: date-time
          description: Creation time for a workspace unit.
        updatedAt:
          type: string
          format: date-time
          description: Last update time for a workspace unit.
    UnitCreate:
      type: object
      description: Fields accepted when creating a workspace unit.
      additionalProperties: false
      required:
        - label
      properties:
        label:
          type: string
          minLength: 1
        pluralLabel:
          type:
            - string
            - "null"
        category:
          type: string
          enum:
            - time
            - quantity
            - flat
          default: quantity
        hoursPerUnit:
          type:
            - number
            - "null"
          minimum: 0
        color:
          type:
            - string
            - "null"
        description:
          type: string
    UnitUpdate:
      type: object
      description: Fields accepted when updating a workspace unit. Only supplied
        fields change.
      additionalProperties: false
      minProperties: 1
      properties:
        label:
          type: string
          minLength: 1
        pluralLabel:
          type:
            - string
            - "null"
        category:
          type: string
          enum:
            - time
            - quantity
            - flat
        hoursPerUnit:
          type:
            - number
            - "null"
          minimum: 0
        color:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
    RatePackCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/RatePack"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    RatePackItemCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/RatePackItem"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    IncentivePackCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/IncentivePack"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    IncentiveProgramCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/IncentiveProgram"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ProjectIncentiveCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProjectIncentive"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    FringeCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Fringe"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ProjectFringeCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProjectFringe"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    GlobalCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Global"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ProjectGlobalCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProjectGlobal"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    CurrencyCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Currency"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ProjectCurrencyCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProjectCurrency"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    FringeGroupCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/FringeGroup"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ProjectFringeGroupCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProjectFringeGroup"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    TagCollection:
      type: object
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Tag"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    UnitCollection:
      type: object
      description: Built-in and workspace units.
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Unit"
    RatePackEnableLink:
      type: object
      description: A rate pack enabled for the workspace.
      additionalProperties: false
      required:
        - id
        - ratePackId
        - enabledAt
      properties:
        id:
          $ref: "#/components/schemas/Id"
        ratePackId:
          $ref: "#/components/schemas/Id"
        enabledAt:
          type: string
          format: date-time
    IncentivePackEnableLink:
      type: object
      description: An incentive pack enabled for the workspace.
      additionalProperties: false
      required:
        - id
        - incentivePackId
        - enabledAt
      properties:
        id:
          $ref: "#/components/schemas/Id"
        incentivePackId:
          $ref: "#/components/schemas/Id"
        enabledAt:
          type: string
          format: date-time
    ProjectStatus:
      type: string
      description: Project status.
      enum:
        - active
        - archived
    ProjectAccess:
      oneOf:
        - type: object
          required:
            - state
            - effectivePlanId
          additionalProperties: false
          properties:
            state:
              type: string
              const: available
            effectivePlanId:
              type: string
        - type: object
          required:
            - state
            - effectivePlanId
            - reason
            - remediation
          additionalProperties: false
          properties:
            state:
              type: string
              const: locked
            effectivePlanId:
              type: string
            reason:
              type: string
              enum:
                - project_limit
                - subscription_restricted
                - contract_restricted
            remediation:
              type: string
              enum:
                - upgrade
                - recover_payment
                - reactivate_subscription
                - contact_sales
    ProjectTag:
      type: object
      required:
        - id
        - name
        - color
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        color:
          type: string
          description: Color used for the tag in Saturation.
    ProjectCreator:
      type: object
      required:
        - id
        - name
        - image
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        image:
          type:
            - string
            - "null"
          description: Profile image URL.
    Project:
      type: object
      description: A production project with its budget, transactions, documents, and
        Library items.
      required:
        - id
        - slug
        - name
        - status
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id: &a1
          $ref: "#/components/schemas/Id"
        slug: &a2
          type: string
          description: The project's human handle, unique per workspace.
          examples:
            - q3-feature-doc
        name: &a3
          type: string
          description: Display name.
          examples:
            - Q3 Feature Doc
        emoji: &a4
          type:
            - string
            - "null"
          description: Emoji shown with the project.
        image: &a5
          type:
            - string
            - "null"
          description: Cover image URL.
        status: &a6
          $ref: "#/components/schemas/ProjectStatus"
        summary: &a7
          type:
            - string
            - "null"
          description: A short project summary.
        spaceId: &a8
          description: Space containing the project, or `null` when ungrouped.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        projectType: &a9
          type:
            - string
            - "null"
          description: Production format, such as Feature film or Commercial.
        tags: &a10
          type: array
          items:
            $ref: "#/components/schemas/ProjectTag"
        createdBy: &a11
          description: Person who created the project.
          anyOf:
            - $ref: "#/components/schemas/ProjectCreator"
            - type: "null"
        createdAt: &a12
          type: string
          format: date-time
          description: ISO 8601 creation time.
        updatedAt: &a13
          type: string
          format: date-time
          description: ISO 8601 last update time.
        access: &a14
          $ref: "#/components/schemas/ProjectAccess"
    ProjectDefaultBudget:
      type: object
      required:
        - budgetId
        - estimatePhaseId
      additionalProperties: false
      properties:
        budgetId:
          $ref: "#/components/schemas/Id"
        estimatePhaseId:
          $ref: "#/components/schemas/Id"
    ProjectCreated:
      type: object
      additionalProperties: false
      required:
        - id
        - slug
        - name
        - status
        - createdAt
        - updatedAt
        - defaultBudget
      properties:
        id: *a1
        slug: *a2
        name: *a3
        emoji: *a4
        image: *a5
        status: *a6
        summary: *a7
        spaceId: *a8
        projectType: *a9
        tags: *a10
        createdBy: *a11
        createdAt: *a12
        updatedAt: *a13
        access: *a14
        defaultBudget:
          $ref: "#/components/schemas/ProjectDefaultBudget"
    ProjectCreate:
      type: object
      description: Fields accepted when creating a project.
      required:
        - name
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
          examples:
            - Q3 Feature Doc
        slug:
          type: string
          description: Unique project handle. Generated from `name` when omitted.
        emoji:
          type:
            - string
            - "null"
        image:
          type:
            - string
            - "null"
        summary:
          type:
            - string
            - "null"
        spaceId:
          description: Space containing the project.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        projectType:
          type:
            - string
            - "null"
          description: Production format, such as Feature film or Commercial.
        tagIds:
          type: array
          description: Project tag IDs to assign. Duplicate IDs are ignored.
          items:
            $ref: "#/components/schemas/Id"
    ProjectUpdate:
      type: object
      description: Fields accepted when updating a project. Only supplied fields
        change. `status` accepts `active` or `archived`.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        slug:
          type: string
        emoji:
          type:
            - string
            - "null"
        image:
          type:
            - string
            - "null"
        summary:
          type:
            - string
            - "null"
        spaceId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        status:
          type: string
          enum:
            - active
            - archived
        projectType:
          type:
            - string
            - "null"
          description: Project type shown in Saturation.
        tagIds:
          type: array
          description: Replaces the project's tags. Send an empty array to remove all tags.
          items:
            $ref: "#/components/schemas/Id"
    ProjectList:
      type: object
      description: A page of projects.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Project"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    Space:
      type: object
      description: A folder that groups projects and can sit inside another space.
      required:
        - id
        - slug
        - name
        - archived
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        slug:
          type: string
          description: The space's human handle (unique per workspace).
          examples:
            - features
        name:
          type: string
          examples:
            - Features
        image:
          type:
            - string
            - "null"
        parentId:
          description: Parent space for nesting, or `null` for a top-level space.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        archived:
          type: boolean
          description: Whether the space is archived.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    SpaceCreate:
      type: object
      description: Fields accepted when creating a space.
      required:
        - name
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
          examples:
            - Features
        slug:
          type: string
          description: Unique space handle. Generated from `name` when omitted.
        image:
          type:
            - string
            - "null"
        parentId:
          description: Parent space, or `null` for a top-level space.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
    SpaceUpdate:
      type: object
      description: Fields accepted when updating a space. Only supplied fields change.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        slug:
          type: string
        image:
          type:
            - string
            - "null"
        parentId:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        archived:
          type: boolean
    SpaceList:
      type: object
      description: A page of spaces.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Space"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ContactType:
      type: string
      description: Contact type. Vendors are organizations; contractors and employees
        are people.
      enum:
        - contractor
        - employee
        - company
        - vendor
    ContactDocumentRef:
      type: object
      description: A document shown with a contact.
      required:
        - id
        - name
        - size
        - mimeType
        - status
        - description
        - classification
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        size:
          type: integer
          format: int64
        mimeType:
          type: string
        status:
          type: string
        description:
          type:
            - string
            - "null"
        classification:
          type:
            - string
            - "null"
    ContactTransactionRef:
      type: object
      description: A transaction shown with a contact.
      required:
        - id
        - description
        - amount
        - timestamp
        - status
        - merchant
        - logoUrl
        - category
        - projectId
        - budgetLineId
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        description:
          type:
            - string
            - "null"
        amount:
          type:
            - integer
            - "null"
          format: int64
        timestamp:
          type:
            - string
            - "null"
          format: date-time
        status:
          type: string
        merchant:
          type:
            - string
            - "null"
        logoUrl:
          type:
            - string
            - "null"
        category:
          type:
            - string
            - "null"
        projectId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        budgetLineId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
    Contact:
      type: object
      description: A vendor, crew member, or other payee in the workspace.
      required:
        - id
        - displayName
        - track1099
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        displayName:
          type: string
          description: Display name for the contact.
          examples:
            - Aerial Imaging LLC
        name:
          type:
            - string
            - "null"
          description: Person or primary contact name.
        company:
          type:
            - string
            - "null"
        title:
          type:
            - string
            - "null"
          description: Role or job title, such as `Director of Photography`.
        type:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/ContactType"
            - type: "null"
        email:
          type:
            - string
            - "null"
        phone:
          type:
            - string
            - "null"
        address:
          type:
            - string
            - "null"
          description: Free-form address as entered.
        website:
          type:
            - string
            - "null"
        instagram:
          type:
            - string
            - "null"
        imdb:
          type:
            - string
            - "null"
        rate:
          description: Default day or labor rate.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Money"
            - type: "null"
        track1099:
          type: boolean
          description: Whether this contact is tracked for 1099 reporting.
        taxIdLast4:
          type:
            - string
            - "null"
          description: Last four digits of the tax ID.
        hasTaxId:
          type: boolean
          description: Whether a tax ID is on file.
        notes:
          type:
            - string
            - "null"
          description: Markdown notes.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        documents:
          type: array
          description: Documents linked to the contact. Included with `expand=documents`.
          items:
            $ref: "#/components/schemas/ContactDocumentRef"
        transactions:
          type: array
          description: Accessible transactions for the contact. Included with
            `expand=transactions`.
          items:
            $ref: "#/components/schemas/ContactTransactionRef"
    ContactCreate:
      type: object
      description: Fields accepted when creating a contact. Tax and bank account
        numbers are added through documents.
      required:
        - name
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
        company:
          type:
            - string
            - "null"
        title:
          type:
            - string
            - "null"
        type:
          $ref: "#/components/schemas/ContactType"
        email:
          type:
            - string
            - "null"
        phone:
          type:
            - string
            - "null"
        address:
          type:
            - string
            - "null"
        website:
          type:
            - string
            - "null"
        instagram:
          type:
            - string
            - "null"
        imdb:
          type:
            - string
            - "null"
        rate:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Money"
            - type: "null"
        track1099:
          type: boolean
        notes:
          type:
            - string
            - "null"
    ContactUpdate:
      type: object
      description: Fields accepted when updating a contact. Only supplied fields change.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          minLength: 1
        company:
          type:
            - string
            - "null"
        title:
          type:
            - string
            - "null"
        type:
          $ref: "#/components/schemas/ContactType"
        email:
          type:
            - string
            - "null"
        phone:
          type:
            - string
            - "null"
        address:
          type:
            - string
            - "null"
        website:
          type:
            - string
            - "null"
        instagram:
          type:
            - string
            - "null"
        imdb:
          type:
            - string
            - "null"
        rate:
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Money"
            - type: "null"
        track1099:
          type: boolean
        notes:
          type:
            - string
            - "null"
    ContactList:
      type: object
      description: A page of contacts.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Contact"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    ContactExpand:
      type: string
      description: Related contact data to include.
      enum:
        - documents
        - transactions
    CommentTargetKind:
      type: string
      description: Resource type associated with a comment.
      enum:
        - project
        - budgetLine
        - transaction
        - purchaseOrder
        - contact
        - document
    CommentTarget:
      type: object
      description: Resource associated with a comment.
      required:
        - kind
        - id
      additionalProperties: false
      properties:
        kind:
          $ref: "#/components/schemas/CommentTargetKind"
        id:
          $ref: "#/components/schemas/Id"
    CommentAuthor:
      type: object
      required:
        - id
        - name
        - avatar
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        avatar:
          type:
            - string
            - "null"
    CommentTag:
      type: object
      required:
        - id
        - targetType
        - targetId
        - label
        - kind
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        targetType:
          type: string
        targetId:
          $ref: "#/components/schemas/Id"
        label:
          type: string
        kind:
          type: string
          enum:
            - mention
            - anchor
    CommentTagWrite:
      type: object
      required:
        - targetType
        - targetId
        - label
      additionalProperties: false
      properties:
        targetType:
          type: string
          minLength: 1
        targetId:
          $ref: "#/components/schemas/Id"
        label:
          type: string
          minLength: 1
        kind:
          type: string
          enum:
            - mention
            - anchor
    CommentReaction:
      type: object
      required:
        - emoji
        - count
        - users
      additionalProperties: false
      properties:
        emoji:
          type: string
        count:
          type: integer
          minimum: 0
        users:
          type: array
          items:
            type: object
            required:
              - id
              - name
            additionalProperties: false
            properties:
              id:
                $ref: "#/components/schemas/Id"
              name:
                type: string
    Comment:
      type: object
      description: A comment on a project resource. Replies reference the first
        comment with `threadId`.
      required:
        - id
        - projectId
        - author
        - content
        - resolved
        - tags
        - reactions
        - replyCount
        - readByCurrentUser
        - edited
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        projectId:
          $ref: "#/components/schemas/Id"
        threadId:
          description: The root comment id when this is a reply; `null` for a root comment.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        target:
          description: Resource associated with the comment.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/CommentTarget"
            - type: "null"
        author:
          $ref: "#/components/schemas/CommentAuthor"
        content:
          type: string
          description: Markdown comment body.
        resolved:
          type: boolean
          description: Whether the comment thread is resolved.
        tags:
          type: array
          items:
            $ref: "#/components/schemas/CommentTag"
        reactions:
          type: array
          items:
            $ref: "#/components/schemas/CommentReaction"
        replyCount:
          type: integer
          minimum: 0
        readByCurrentUser:
          type: boolean
        edited:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    CommentCreate:
      type: object
      description: Fields accepted when creating a comment.
      required:
        - content
        - target
      additionalProperties: false
      properties:
        content:
          type: string
          minLength: 1
        target:
          $ref: "#/components/schemas/CommentTarget"
        threadId:
          description: Root comment ID when adding a reply.
          anyOf:
            - allOf:
                - $ref: "#/components/schemas/Id"
            - type: "null"
        tags:
          type: array
          description: Mentions and resource links in the comment.
          items:
            $ref: "#/components/schemas/CommentTagWrite"
    CommentUpdate:
      type: object
      description: Fields accepted when updating a comment. Only the author can change
        `content`.
      additionalProperties: false
      minProperties: 1
      properties:
        content:
          type: string
          minLength: 1
        resolved:
          type: boolean
        tags:
          type: array
          description: Replaces the comment's mentions and resource links.
          items:
            $ref: "#/components/schemas/CommentTagWrite"
        reactionEmojis:
          type: array
          description: Replaces the current user's reactions. Duplicate emoji are ignored.
          items:
            type: string
            minLength: 1
    CommentList:
      type: object
      description: A page of comments.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Comment"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether some matching items were omitted from the response.
    PrincipalType:
      type: string
      description: Type of identity associated with the token.
      enum:
        - user
        - service
    WorkspaceReach:
      type: object
      description: A workspace and role associated with the token.
      required:
        - workspaceId
        - workspaceRole
      additionalProperties: false
      properties:
        workspaceId:
          $ref: "#/components/schemas/Id"
        workspaceName:
          type: string
          description: Workspace name.
        workspaceRole:
          $ref: "#/components/schemas/WorkspaceRole"
    WorkspaceRole:
      type: string
      description: Role in the workspace.
      enum:
        - owner
        - admin
        - accountant
        - edit
        - comment
        - view
    Me:
      type: object
      description: Identity and workspaces associated with the token.
      required:
        - id
        - type
        - workspaces
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        type:
          $ref: "#/components/schemas/PrincipalType"
        email:
          type: string
          format: email
          description: Email address. Present for user identities.
        name:
          type: string
          description: Display name.
        workspaces:
          type: array
          description: Workspaces associated with the token.
          items:
            $ref: "#/components/schemas/WorkspaceReach"
      example:
        id: usr_4f1a8c2e
        type: user
        email: producer@example.com
        name: Dana Producer
        workspaces:
          - workspaceId: ws_2b9d7a1f
            workspaceName: Paradigm Pictures
            workspaceRole: admin
    PaymentRequestStatus:
      type: string
      description: Current payment-request status. `unknown` means the status is
        unavailable.
      enum:
        - submitted
        - pending
        - approved
        - paid
        - rejected
        - canceled
        - unknown
    PaymentStatus:
      type: string
      description: Current payment status.
      enum:
        - requested
        - needs_approval
        - scheduled
        - sending
        - settled
        - returned
        - failed
        - rejected
        - canceled
    PaymentRequestExpand:
      type: string
      description: Related record available through `expand`.
      enum:
        - contact
        - purchaseOrder
        - document
        - payment
        - transactions
        - budgetLine
    PaymentExpand:
      type: string
      description: Related record available through `expand`.
      enum:
        - request
        - purchaseOrder
        - transactions
        - contact
        - budgetLine
        - document
    PaymentContactLink:
      type: object
      required:
        - id
        - name
        - displayTitle
        - company
        - email
        - type
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type:
            - string
            - "null"
        displayTitle:
          type:
            - string
            - "null"
        company:
          type:
            - string
            - "null"
        email:
          type:
            - string
            - "null"
        type:
          type:
            - string
            - "null"
    PaymentPurchaseOrderLink:
      type: object
      required:
        - id
        - projectId
        - number
        - name
        - status
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        projectId:
          type:
            - string
            - "null"
        number:
          type:
            - string
            - "null"
        name:
          type:
            - string
            - "null"
        status:
          type: string
    PaymentDocumentLink:
      type: object
      required:
        - id
        - projectId
        - name
        - mimeType
        - status
        - size
        - classification
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        projectId:
          type:
            - string
            - "null"
        name:
          type: string
        mimeType:
          type:
            - string
            - "null"
        status:
          type: string
        size:
          type: integer
        classification:
          type:
            - string
            - "null"
    PaymentBudgetLineLink:
      type: object
      required:
        - id
        - accountId
        - description
        - type
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        accountId:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        type:
          type:
            - string
            - "null"
    PaymentTransactionLink:
      type: object
      required:
        - id
        - projectId
        - amount
        - description
        - status
        - timestamp
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        projectId:
          type:
            - string
            - "null"
        amount:
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
        description:
          type:
            - string
            - "null"
        status:
          type: string
        timestamp:
          type:
            - string
            - "null"
          format: date-time
    PaymentRequestBase:
      type: object
      description: A request to pay a person or company.
      required: &a15
        - id
        - workspaceId
        - projectId
        - purchaseOrderId
        - contactId
        - budgetLineId
        - amount
        - description
        - memo
        - dueDate
        - method
        - status
        - submittedAt
        - approvedAt
        - rejectedAt
        - completedAt
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id: &a16
          $ref: "#/components/schemas/Id"
        workspaceId: &a17
          $ref: "#/components/schemas/Id"
        projectId: &a18
          type:
            - string
            - "null"
        purchaseOrderId: &a19
          type:
            - string
            - "null"
        contactId: &a20
          type:
            - string
            - "null"
        budgetLineId: &a21
          type:
            - string
            - "null"
        amount: &a22
          $ref: "#/components/schemas/Money"
        description: &a23
          type:
            - string
            - "null"
        memo: &a24
          type:
            - string
            - "null"
        dueDate: &a25
          type:
            - string
            - "null"
          format: date-time
        method: &a26
          type:
            - string
            - "null"
        status: &a27
          $ref: "#/components/schemas/PaymentRequestStatus"
        submittedAt: &a28
          type: string
          format: date-time
        approvedAt: &a29
          type:
            - string
            - "null"
          format: date-time
        rejectedAt: &a30
          type:
            - string
            - "null"
          format: date-time
        completedAt: &a31
          type:
            - string
            - "null"
          format: date-time
        createdAt: &a32
          type: string
          format: date-time
        updatedAt: &a33
          type: string
          format: date-time
    PaymentBase:
      type: object
      description: A payment and its current status.
      required: &a34
        - id
        - workspaceId
        - projectId
        - paymentRequestId
        - purchaseOrderId
        - contactId
        - budgetLineId
        - status
        - amount
        - destinationAmount
        - rail
        - description
        - memo
        - notes
        - scheduledFor
        - expectedArrivalAt
        - destination
        - cancellationRequested
        - needsSupport
        - failureReason
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id: &a35
          $ref: "#/components/schemas/Id"
        workspaceId: &a36
          $ref: "#/components/schemas/Id"
        projectId: &a37
          type:
            - string
            - "null"
        paymentRequestId: &a38
          type:
            - string
            - "null"
        purchaseOrderId: &a39
          type:
            - string
            - "null"
        contactId: &a40
          type:
            - string
            - "null"
        budgetLineId: &a41
          type:
            - string
            - "null"
        status: &a42
          $ref: "#/components/schemas/PaymentStatus"
        amount: &a43
          $ref: "#/components/schemas/Money"
        destinationAmount: &a44
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
        rail: &a45
          type:
            - string
            - "null"
        description: &a46
          type:
            - string
            - "null"
        memo: &a47
          type:
            - string
            - "null"
        notes: &a48
          type:
            - string
            - "null"
        scheduledFor: &a49
          type:
            - string
            - "null"
          format: date-time
        expectedArrivalAt: &a50
          type:
            - string
            - "null"
          format: date-time
        destination: &a51
          oneOf:
            - type: object
              required:
                - bankName
                - accountType
                - accountLast4
                - network
              additionalProperties: false
              properties:
                bankName:
                  type:
                    - string
                    - "null"
                accountType:
                  type:
                    - string
                    - "null"
                accountLast4:
                  type:
                    - string
                    - "null"
                network:
                  type:
                    - string
                    - "null"
            - type: "null"
        cancellationRequested: &a52
          type: boolean
        needsSupport: &a53
          type: boolean
        failureReason: &a54
          type:
            - string
            - "null"
        createdAt: &a55
          type: string
          format: date-time
        updatedAt: &a56
          type: string
          format: date-time
    PaymentRequest:
      type: object
      required: *a15
      additionalProperties: false
      properties:
        id: *a16
        workspaceId: *a17
        projectId: *a18
        purchaseOrderId: *a19
        contactId: *a20
        budgetLineId: *a21
        amount: *a22
        description: *a23
        memo: *a24
        dueDate: *a25
        method: *a26
        status: *a27
        submittedAt: *a28
        approvedAt: *a29
        rejectedAt: *a30
        completedAt: *a31
        createdAt: *a32
        updatedAt: *a33
        contact:
          oneOf:
            - $ref: "#/components/schemas/PaymentContactLink"
            - type: "null"
        purchaseOrder:
          oneOf:
            - $ref: "#/components/schemas/PaymentPurchaseOrderLink"
            - type: "null"
        document:
          oneOf:
            - $ref: "#/components/schemas/PaymentDocumentLink"
            - type: "null"
        payment:
          oneOf:
            - $ref: "#/components/schemas/PaymentBase"
            - type: "null"
        transactions:
          type: array
          items:
            $ref: "#/components/schemas/PaymentTransactionLink"
        budgetLine:
          oneOf:
            - $ref: "#/components/schemas/PaymentBudgetLineLink"
            - type: "null"
    Payment:
      type: object
      required: *a34
      additionalProperties: false
      properties:
        id: *a35
        workspaceId: *a36
        projectId: *a37
        paymentRequestId: *a38
        purchaseOrderId: *a39
        contactId: *a40
        budgetLineId: *a41
        status: *a42
        amount: *a43
        destinationAmount: *a44
        rail: *a45
        description: *a46
        memo: *a47
        notes: *a48
        scheduledFor: *a49
        expectedArrivalAt: *a50
        destination: *a51
        cancellationRequested: *a52
        needsSupport: *a53
        failureReason: *a54
        createdAt: *a55
        updatedAt: *a56
        request:
          oneOf:
            - $ref: "#/components/schemas/PaymentRequestBase"
            - type: "null"
        purchaseOrder:
          oneOf:
            - $ref: "#/components/schemas/PaymentPurchaseOrderLink"
            - type: "null"
        transactions:
          type: array
          items:
            $ref: "#/components/schemas/PaymentTransactionLink"
        contact:
          oneOf:
            - $ref: "#/components/schemas/PaymentContactLink"
            - type: "null"
        budgetLine:
          oneOf:
            - $ref: "#/components/schemas/PaymentBudgetLineLink"
            - type: "null"
        document:
          oneOf:
            - $ref: "#/components/schemas/PaymentDocumentLink"
            - type: "null"
    PaymentTimelineEvent:
      type: object
      required:
        - id
        - type
        - label
        - occurredAt
        - actor
        - related
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        type:
          type: string
        label:
          type: string
        occurredAt:
          type: string
          format: date-time
        actor:
          oneOf:
            - type: object
              required:
                - id
                - name
                - avatarUrl
              additionalProperties: false
              properties:
                id:
                  $ref: "#/components/schemas/Id"
                name:
                  type: string
                avatarUrl:
                  type:
                    - string
                    - "null"
            - type: "null"
        related:
          type: array
          items:
            type: object
            required:
              - type
              - id
            additionalProperties: false
            properties:
              type:
                type: string
                enum:
                  - document
                  - payment_request
                  - payment
                  - transaction
                  - purchase_order
                  - approval
              id:
                $ref: "#/components/schemas/Id"
    PaymentTimelinePage:
      type: object
      required:
        - data
        - nextCursor
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PaymentTimelineEvent"
        nextCursor:
          type:
            - string
            - "null"
    PaymentRequestList:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PaymentRequest"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
    PaymentList:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Payment"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
    PurchaseOrderStatus:
      type: string
      description: Current purchase order status.
      enum:
        - draft
        - pending
        - approved
        - rejected
        - actualizing
        - paid
        - void
      examples:
        - pending
    PurchaseOrderActivityType:
      type: string
      description: Activity shown in the purchase order Activity column.
      enum:
        - invoice_requested
        - invoice_received
        - invoice_rejected
        - payment_requested
        - payment_approval_pending
        - payment_approved
        - payment_processing
        - payment_sent
        - payment_failed
        - payment_returned
        - actualized_needs_review
        - split_needs_review
        - transaction_match_needs_review
    PurchaseOrderActivitySeverity:
      type: string
      enum:
        - neutral
        - info
        - warning
        - danger
        - success
    PurchaseOrderExpand:
      type: string
      description: Related records available through `expand`. Unknown keys return
        `400 expand_invalid`.
      enum:
        - items
        - contact
        - transactions
        - documents
        - paymentRequests
        - payments
        - budgetLine
        - activity
        - summary
    PurchaseOrderSort:
      type: string
      description: Fields available for sorting purchase orders.
      enum:
        - number
        - name
        - dueDate
        - serviceStartAt
        - serviceEndAt
        - status
        - sort
        - createdAt
        - updatedAt
    PurchaseOrderContactRef:
      type: object
      description: Vendor details included with a purchase order.
      required:
        - id
        - displayName
        - name
        - company
        - email
        - type
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        displayName:
          type: string
        name:
          type:
            - string
            - "null"
        company:
          type:
            - string
            - "null"
        email:
          type:
            - string
            - "null"
        type:
          type:
            - string
            - "null"
    PurchaseOrderTransactionRef:
      type: object
      description: Transaction details included with a purchase order.
      required:
        - id
        - projectId
        - purchaseOrderId
        - amount
        - description
        - timestamp
        - status
        - type
        - contactId
        - budgetLineId
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        projectId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        purchaseOrderId:
          $ref: "#/components/schemas/Id"
        amount:
          type:
            - integer
            - "null"
          format: int64
        description:
          type:
            - string
            - "null"
        timestamp:
          type:
            - string
            - "null"
          format: date-time
        status:
          type: string
        type:
          type:
            - string
            - "null"
        contactId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        budgetLineId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
    PurchaseOrderDocumentRef:
      type: object
      description: Document details included with a purchase order.
      required:
        - id
        - name
        - mimeType
        - status
        - size
        - classification
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        mimeType:
          type: string
        status:
          type: string
        size:
          type: integer
          format: int64
        classification:
          type:
            - string
            - "null"
    PurchaseOrderBudgetLineRef:
      type: object
      description: Budget line details included with a purchase order.
      required:
        - id
        - accountId
        - type
        - description
        - parentId
        - sort
        - contactId
        - lineColor
        - emoji
        - notes
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        accountId:
          type:
            - string
            - "null"
        type:
          type: string
        description:
          type:
            - string
            - "null"
        parentId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        sort:
          type:
            - string
            - "null"
        contactId:
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        lineColor:
          type:
            - string
            - "null"
        emoji:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
    PurchaseOrder:
      type: object
      description: A purchase order in Saturation.
      required:
        - id
        - workspaceId
        - projectId
        - status
        - currency
        - exchangeRate
        - exchangeRateSource
        - amount
        - createdAt
        - updatedAt
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        workspaceId:
          $ref: "#/components/schemas/Id"
        projectId:
          description: Assigned project ID, or `null` when unassigned.
          oneOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        number:
          type:
            - string
            - "null"
          description: Purchase order number, such as `PO-0042`.
        name:
          type:
            - string
            - "null"
          description: Purchase order name.
        status:
          $ref: "#/components/schemas/PurchaseOrderStatus"
        contactId:
          type:
            - string
            - "null"
          description: Vendor contact ID.
        budgetLineId:
          type:
            - string
            - "null"
          description: Budget line ID.
        dueDate:
          type:
            - string
            - "null"
          format: date
          description: Payment due date.
        serviceStartAt:
          type:
            - string
            - "null"
          format: date
          description: First service date.
        serviceEndAt:
          type:
            - string
            - "null"
          format: date
          description: Last service date.
        notes:
          type:
            - string
            - "null"
          description: Notes about the purchase order.
        sort:
          type:
            - number
            - "null"
          description: Display order within the project.
        currency:
          type: string
          minLength: 3
          maxLength: 3
          description: Purchase order currency.
        exchangeRate:
          type:
            - number
            - "null"
          description: Rate from the purchase order currency to the workspace currency.
        exchangeRateSource:
          type:
            - string
            - "null"
          description: Where the exchange rate came from.
        createdById:
          type:
            - string
            - "null"
          description: ID of the user who created the purchase order.
        amount:
          allOf:
            - $ref: "#/components/schemas/Money"
          description: Sum of item amounts in the purchase order currency.
        createdAt:
          type: string
          format: date-time
          description: Time the purchase order was created.
        updatedAt:
          type: string
          format: date-time
          description: Time the purchase order was last updated.
        items:
          type: array
          description: Purchase order items. Included with `expand=items`.
          items:
            $ref: "#/components/schemas/PurchaseOrderItem"
        contact:
          description: Vendor contact. Included with `expand=contact`.
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderContactRef"
            - type: "null"
        transactions:
          type: array
          description: Linked transactions. Included with `expand=transactions`.
          items:
            $ref: "#/components/schemas/PurchaseOrderTransactionRef"
        documents:
          type: array
          description: Related documents. Included with `expand=documents`.
          items:
            $ref: "#/components/schemas/PurchaseOrderDocumentRef"
        paymentRequests:
          type: array
          description: Related payment requests. Included with `expand=paymentRequests`.
          items:
            $ref: "#/components/schemas/PaymentRequestBase"
        payments:
          type: array
          description: Related payments. Included with `expand=payments`.
          items:
            $ref: "#/components/schemas/PaymentBase"
        budgetLine:
          description: Budget line charged by the purchase order. Included with
            `expand=budgetLine`.
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderBudgetLineRef"
            - type: "null"
        activity:
          description: Current Activity column details. Included with `expand=activity`.
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderActivitySummary"
            - type: "null"
        summary:
          description: Purchase order totals. Included on detail responses or with
            `expand=summary`.
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderSummary"
            - type: "null"
      examples:
        - id: po_8f2a1c9e
          workspaceId: ws_3b1
          projectId: prj_demo
          number: PO-0042
          name: Camera package rental
          status: pending
          contactId: con_77a
          budgetLineId: bud_5510
          dueDate: 2026-05-20
          serviceStartAt: 2026-05-21
          serviceEndAt: 2026-05-24
          notes: Net-30
          sort: 1000
          createdById: usr_aa1
          amount:
            amount: 152900
            currency: USD
          createdAt: 2026-05-18T14:02:11.000Z
          updatedAt: 2026-05-20T09:31:00.000Z
    PurchaseOrderItem:
      type: object
      description: An item in a purchase order.
      required:
        - id
        - purchaseOrderId
        - sort
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        purchaseOrderId:
          $ref: "#/components/schemas/Id"
        lineNumber:
          type:
            - string
            - "null"
          description: Line number shown in the itemization.
        description:
          type:
            - string
            - "null"
          description: Item description.
        budgetLineId:
          type:
            - string
            - "null"
          description: Budget line ID.
        qty:
          type:
            - string
            - "null"
          description: Quantity or formula.
        unit:
          type:
            - string
            - "null"
          description: Unit, such as `day`, `week`, or `each`.
        rate:
          type:
            - string
            - "null"
          description: Rate or formula.
        amount:
          type:
            - integer
            - "null"
          format: int64
          description: Item total in minor currency units.
        sort:
          type: string
          description: Display order within the purchase order.
      examples:
        - id: poi_1a
          purchaseOrderId: po_8f2a1c9e
          lineNumber: "1"
          description: Alexa Mini LF body
          budgetLineId: bud_5510
          qty: "5"
          unit: day
          rate: "25000"
          amount: 125000
          sort: "1000"
    PurchaseOrderActivityItem:
      type: object
      description: One entry in the purchase order Activity column.
      required:
        - type
        - label
        - severity
        - count
        - sourceIds
      additionalProperties: false
      properties:
        type:
          $ref: "#/components/schemas/PurchaseOrderActivityType"
        label:
          type: string
        severity:
          $ref: "#/components/schemas/PurchaseOrderActivitySeverity"
        count:
          type: integer
          minimum: 0
        sourceIds:
          type: array
          items:
            type: string
    PurchaseOrderActivitySummary:
      type: object
      description: Current purchase order activity.
      required:
        - primaryActivity
        - items
      additionalProperties: false
      properties:
        primaryActivity:
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderActivityItem"
            - type: "null"
        items:
          type: array
          items:
            $ref: "#/components/schemas/PurchaseOrderActivityItem"
    PurchaseOrderSummary:
      type: object
      description: Purchase order totals in its currency.
      required:
        - purchaseOrderId
        - currency
        - amounts
      additionalProperties: false
      properties:
        purchaseOrderId:
          $ref: "#/components/schemas/Id"
        currency:
          type: string
          minLength: 3
          maxLength: 3
        amounts:
          type: object
          required:
            - ordered
            - requested
            - invoiced
            - sent
            - actualized
            - remaining
            - variance
          additionalProperties: false
          properties:
            ordered:
              $ref: "#/components/schemas/Money"
            requested:
              $ref: "#/components/schemas/Money"
            invoiced:
              $ref: "#/components/schemas/Money"
            sent:
              $ref: "#/components/schemas/Money"
            actualized:
              $ref: "#/components/schemas/Money"
            remaining:
              $ref: "#/components/schemas/Money"
            variance:
              $ref: "#/components/schemas/Money"
    PurchaseOrderTimelineEventType:
      type: string
      description: Purchase order history event type.
      enum:
        - created
        - item_added
        - submitted_for_approval
        - approved
        - rejected
        - approval_request_canceled
        - voided
        - transaction_linked
        - transaction_unlinked
        - marked_paid
        - invoice_requested
        - invoice_uploaded
        - attachment_uploaded
        - document_linked
        - decision_recorded
        - decision_undone
        - status_changed
        - approval_decision
        - details_updated
    PurchaseOrderTimelineActor:
      type: object
      required:
        - id
        - name
        - avatarUrl
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        avatarUrl:
          type:
            - string
            - "null"
    PurchaseOrderTimelineEvent:
      type: object
      required:
        - id
        - type
        - label
        - occurredAt
        - actor
        - related
        - superseded
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        type:
          $ref: "#/components/schemas/PurchaseOrderTimelineEventType"
        label:
          type: string
        occurredAt:
          type: string
          format: date-time
        actor:
          oneOf:
            - $ref: "#/components/schemas/PurchaseOrderTimelineActor"
            - type: "null"
        related:
          type: array
          items:
            $ref: "#/components/schemas/PublicResourceRef"
        superseded:
          type: boolean
    PurchaseOrderTimelinePage:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PurchaseOrderTimelineEvent"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
    PurchaseOrderCreate:
      type: object
      description: Fields for a new draft purchase order.
      additionalProperties: false
      properties:
        projectId:
          type: string
          description: Project ID or slug. Omit to leave the purchase order unassigned.
        number:
          type: string
          description: Purchase order number.
        name:
          type: string
          description: Purchase order name.
        contactId:
          type: string
          description: Vendor contact ID.
        budgetLineId:
          type: string
          description: Budget line ID.
        dueDate:
          type: string
          format: date
          description: Payment due date.
        serviceStartAt:
          type: string
          format: date
          description: First service date.
        serviceEndAt:
          type: string
          format: date
          description: Last service date.
        notes:
          type: string
        sort:
          type: number
        items:
          type: array
          maxItems: 100
          description: Items to create with the purchase order.
          items:
            $ref: "#/components/schemas/PurchaseOrderItemWrite"
      examples:
        - number: PO-0042
          name: Camera package rental
          contactId: con_77a
          budgetLineId: bud_5510
          dueDate: 2026-05-20
          serviceStartAt: 2026-05-21
          serviceEndAt: 2026-05-24
          notes: Net-30
          items:
            - description: Alexa Mini LF body
              qty: "5"
              unit: day
              rate: "25000"
    PurchaseOrderUpdate:
      type: object
      description: Fields to update on a draft or rejected purchase order.
      additionalProperties: false
      properties:
        projectId:
          type:
            - string
            - "null"
          description: Project ID or slug. Set to `null` to unassign the purchase order.
        number:
          type:
            - string
            - "null"
        name:
          type:
            - string
            - "null"
        contactId:
          type:
            - string
            - "null"
        budgetLineId:
          type:
            - string
            - "null"
        dueDate:
          type:
            - string
            - "null"
          format: date
        serviceStartAt:
          type:
            - string
            - "null"
          format: date
        serviceEndAt:
          type:
            - string
            - "null"
          format: date
        notes:
          type:
            - string
            - "null"
        sort:
          type:
            - number
            - "null"
      examples:
        - name: Camera package rental (updated)
          notes: Net-45
    PurchaseOrderItemWrite:
      type: object
      description: Fields for a new or updated purchase order item.
      additionalProperties: false
      properties:
        lineNumber:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        budgetLineId:
          type:
            - string
            - "null"
        qty:
          type:
            - string
            - "null"
        unit:
          type:
            - string
            - "null"
        rate:
          type:
            - string
            - "null"
        amount:
          type:
            - integer
            - "null"
          format: int64
          description: Item total in minor currency units. Defaults to `qty × rate`.
        sort:
          type:
            - string
            - "null"
      examples:
        - description: Alexa Mini LF body
          budgetLineId: bud_5510
          qty: "5"
          unit: day
          rate: "25000"
    PurchaseOrderList:
      type: object
      description: A paginated page of purchase orders.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PurchaseOrder"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total number of matches. Included when `withCount=true`.
        truncated:
          type: boolean
          description: Whether the page contains fewer results than requested.
    PurchaseOrderItemList:
      type: object
      description: A page of purchase-order line items.
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PurchaseOrderItem"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total number of matches. Included when `withCount=true`.
        truncated:
          type: boolean
          description: Whether the page contains fewer results than requested.
    SearchKind:
      type: string
      description: Resource types included in search.
      enum:
        - transactions
        - documents
        - contacts
        - budget-lines
        - purchase-orders
      examples:
        - transactions
    SearchHit:
      type: object
      description: One search result.
      required:
        - kind
        - id
        - label
        - score
      additionalProperties: false
      properties:
        kind:
          $ref: "#/components/schemas/SearchKind"
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: ID of the matched resource.
        label:
          type: string
          description: Display label for the result.
          examples:
            - Panavision Camera Package
        snippet:
          type: string
          description: Matching text when it differs from `label`.
          examples:
            - Invoice 4471, Panavision rental
        score:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: Relevance from 0 to 1. Higher values are more relevant.
          examples:
            - 0.62
    SearchResponse:
      type: object
      description: A page of search results ordered by relevance.
      required:
        - data
        - searchedTypes
      additionalProperties: false
      properties:
        data:
          type: array
          description: Results for this page.
          items:
            $ref: "#/components/schemas/SearchHit"
        nextCursor:
          allOf:
            - $ref: "#/components/schemas/NextCursor"
          description: Cursor for the next page. Use it with the same `q` and `types`.
          examples:
            - eyJzIjowLjYyLCJrIjoidHJhbnNhY3Rpb25zIiwiaWQiOiJ0eG5fOGYyYSJ9
        count:
          type: integer
          description: Total matching hits; present only when `withCount=true`.
        searchedTypes:
          type: array
          description: Resource types searched for this request.
          items:
            $ref: "#/components/schemas/SearchKind"
          examples:
            - - transactions
              - documents
              - budget-lines
    TransactionSource:
      type: string
      description: How the transaction entered Saturation. Financial fields are
        editable only for `manual` transactions.
      enum:
        - manual
        - plaid
        - saturation_pay
        - saturation_credit
      examples:
        - manual
    TransactionType:
      type: string
      description: Transaction type. The API may return values not listed below.
      x-extensible-enum: true
      enum:
        - SaturationPCard
        - ACH
        - Cash
        - Check
        - CreditCard
        - Deposit
        - ETransfer
        - Invoice
        - Projection
        - TimeCard
        - Wire
        - Withdrawal
      examples:
        - CreditCard
    TransactionManualType:
      type: string
      description: Transaction types available for manual transactions.
      enum:
        - Invoice
        - Projection
        - Cash
        - Check
        - Wire
        - ACH
        - CreditCard
        - TimeCard
        - ETransfer
      examples:
        - Invoice
    TransactionStatus:
      type: string
      description: Current transaction status. Available statuses vary by source.
      enum:
        - unpaid
        - pending
        - posted
        - void
        - needs_review
        - projected
        - rejected
      examples:
        - posted
    ExchangeRateSource:
      type: string
      description: Source of the exchange rate. The API may return values not listed below.
      x-extensible-enum: true
      enum:
        - bank
        - api
        - user
      examples:
        - bank
    TransactionExpandKey:
      type: string
      description: Related records available through `expand`. Unknown keys or nesting
        beyond two levels return `400 expand_invalid`.
      enum:
        - contact
        - documents
        - items
        - account
        - purchaseOrder
        - items.account
      examples:
        - items.account
    TransactionSortField:
      type: string
      description: Fields available for sorting. The default is `timestamp` in
        descending order.
      enum:
        - timestamp
        - amount
        - status
        - type
        - description
        - createdAt
        - updatedAt
      default: timestamp
      examples:
        - timestamp
    TransactionItem:
      type: object
      description: An item in an itemized transaction. Budget coding belongs to each
        item instead of the transaction.
      additionalProperties: false
      required:
        - id
        - lineNumber
        - amount
        - tagIds
        - tags
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Transaction item ID.
          examples:
            - txi_4a1b2c3d
        lineNumber:
          type:
            - string
            - "null"
          description: Line number shown in the itemization.
          examples:
            - "1"
        description:
          type:
            - string
            - "null"
          description: Item description.
        budgetLineId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Budget line ID.
        fringeId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Applied fringe ID.
        contactId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Contact for this item.
        qty:
          type:
            - string
            - "null"
          description: Quantity or formula.
          examples:
            - "3"
        unit:
          type:
            - string
            - "null"
          description: Unit, such as `Day`, `Hour`, or `Flat`.
          examples:
            - Day
        customUnitId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Custom unit ID.
        rate:
          type:
            - string
            - "null"
          description: Rate or formula.
        amount:
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
        overtime:
          type:
            - string
            - "null"
          description: Overtime amount or formula.
        taxable:
          type:
            - string
            - "null"
          description: Taxable amount or formula.
        nonTaxable:
          type:
            - string
            - "null"
          description: Non-taxable amount or formula.
        account:
          description: Budget account for the item. Included with `expand=items.account`.
          oneOf:
            - $ref: "#/components/schemas/TransactionAccountRef"
            - type: "null"
        tagIds:
          type: array
          description: Tag IDs assigned to this item.
          items:
            $ref: "#/components/schemas/Id"
        tags:
          type: array
          description: Tags assigned to this item.
          items:
            $ref: "#/components/schemas/TransactionItemTag"
    TransactionItemTag:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - color
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
        color:
          type:
            - string
            - "null"
    TransactionItemCreate:
      type: object
      description: Fields for a new transaction item.
      additionalProperties: false
      required:
        - amount
      properties:
        lineNumber:
          type: string
        description:
          type: string
        budgetLineId:
          $ref: "#/components/schemas/Id"
        fringeId:
          $ref: "#/components/schemas/Id"
        contactId:
          $ref: "#/components/schemas/Id"
        qty:
          type: string
        unit:
          type: string
        customUnitId:
          $ref: "#/components/schemas/Id"
        rate:
          type: string
        amount:
          $ref: "#/components/schemas/Money"
        overtime:
          type: string
        taxable:
          type: string
        nonTaxable:
          type: string
        tagIds:
          type: array
          description: Tag IDs to assign. Duplicate IDs are ignored.
          items:
            $ref: "#/components/schemas/Id"
    TransactionItemPatch:
      type: object
      description: Fields to update on a transaction item. Read-only fields return
        `422 field_read_only`.
      additionalProperties: false
      minProperties: 1
      properties:
        lineNumber:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        budgetLineId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        fringeId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        contactId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        qty:
          type:
            - string
            - "null"
        unit:
          type:
            - string
            - "null"
        customUnitId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        rate:
          type:
            - string
            - "null"
        amount:
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
        overtime:
          type:
            - string
            - "null"
        taxable:
          type:
            - string
            - "null"
        nonTaxable:
          type:
            - string
            - "null"
        tagIds:
          type: array
          description: Replaces the item's tags. Send an empty array to remove all tags.
          items:
            $ref: "#/components/schemas/Id"
    TransactionAccountRef:
      type: object
      description: Budget account included through `expand=account` or
        `expand=items.account`.
      additionalProperties: false
      required:
        - id
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
          examples:
            - Camera
        code:
          type:
            - string
            - "null"
          description: Account code.
          examples:
            - "1200"
    Transaction:
      type: object
      description: A transaction in Saturation. Money uses minor currency units.
      additionalProperties: false
      required:
        - id
        - source
        - type
        - status
        - isReversal
        - amount
        - timestamp
        - isItemized
        - actualized
        - projectId
        - createdAt
        - updatedAt
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Transaction ID.
          examples:
            - txn_8f2a1c9e
        source:
          $ref: "#/components/schemas/TransactionSource"
        sourceId:
          type:
            - string
            - "null"
          description: Reference supplied by the transaction source.
        type:
          anyOf:
            - $ref: "#/components/schemas/TransactionType"
            - type: "null"
        status:
          $ref: "#/components/schemas/TransactionStatus"
        isReversal:
          type: boolean
          description: Whether the transaction is a refund or another reversal.
        amount:
          $ref: "#/components/schemas/Money"
        exchangeRate:
          type:
            - number
            - "null"
          description: Exchange rate to the workspace currency.
        exchangeRateSource:
          oneOf:
            - $ref: "#/components/schemas/ExchangeRateSource"
            - type: "null"
        timestamp:
          type: string
          format: date-time
          description: Time the transaction occurred.
          examples:
            - 2026-05-20T14:03:00.000Z
        description:
          type:
            - string
            - "null"
        merchant:
          type:
            - string
            - "null"
          description: Merchant name supplied by the transaction source.
        logoUrl:
          type:
            - string
            - "null"
          format: uri
          description: Merchant logo URL.
        category:
          type:
            - string
            - "null"
          description: Category supplied by the transaction source.
        sourceLast4:
          type:
            - string
            - "null"
          description: Last four characters of the source account or card.
        sourceName:
          type:
            - string
            - "null"
          description: Name of the source account or card.
        number:
          type:
            - string
            - "null"
          description: Document, check, or invoice number.
        ref:
          type:
            - string
            - "null"
          description: External reference.
        payId:
          type:
            - string
            - "null"
          description: Related Saturation Pay payment ID.
        notes:
          type:
            - string
            - "null"
          description: Notes about the transaction.
        contactId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Assigned contact ID.
        projectId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Assigned project ID, or `null` when unassigned.
        budgetLineId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Budget line ID. Itemized transactions store this on each item
            instead.
        fringeId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        isItemized:
          type: boolean
          description: Whether the transaction has items.
        actualized:
          type: boolean
          description: Whether the transaction is included in budget actuals.
        purchaseOrderId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Linked purchase order ID.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        contact:
          description: Assigned contact. Included with `expand=contact`.
          oneOf:
            - $ref: "#/components/schemas/TransactionContactRef"
            - type: "null"
        documents:
          description: Related documents. Included with `expand=documents`.
          type: array
          items:
            $ref: "#/components/schemas/TransactionDocumentRef"
        items:
          type: array
          description: Transaction items. Included with `expand=items`.
          items:
            $ref: "#/components/schemas/TransactionItem"
        account:
          description: Budget account. Included with `expand=account`.
          oneOf:
            - $ref: "#/components/schemas/TransactionAccountRef"
            - type: "null"
        purchaseOrder:
          description: Linked purchase order. Included with `expand=purchaseOrder`.
          oneOf:
            - $ref: "#/components/schemas/TransactionPurchaseOrderRef"
            - type: "null"
    TransactionContactRef:
      type: object
      description: Contact details included with a transaction.
      required:
        - id
        - name
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type:
            - string
            - "null"
    TransactionDocumentRef:
      type: object
      description: Document details included with a transaction.
      required:
        - id
        - name
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type:
            - string
            - "null"
    TransactionPurchaseOrderRef:
      type: object
      description: Purchase order details included with a transaction.
      required:
        - id
        - number
      additionalProperties: false
      properties:
        id:
          $ref: "#/components/schemas/Id"
        number:
          type:
            - string
            - "null"
    TransactionManualCreate:
      type: object
      description: Fields for a new manual transaction.
      additionalProperties: false
      required:
        - type
        - amount
        - timestamp
      properties:
        type:
          $ref: "#/components/schemas/TransactionManualType"
        amount:
          $ref: "#/components/schemas/Money"
        timestamp:
          type: string
          format: date-time
          description: Transaction time. A date without a time is recorded at midnight UTC.
        status:
          allOf:
            - $ref: "#/components/schemas/TransactionStatus"
          description: Transaction status. Defaults to `posted`.
        description:
          type: string
        projectId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Project ID or slug. Omit to leave the transaction unassigned.
        contactId:
          $ref: "#/components/schemas/Id"
        budgetLineId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Budget line ID. Omit for an itemized transaction.
        fringeId:
          $ref: "#/components/schemas/Id"
        number:
          type: string
        ref:
          type: string
        notes:
          type: string
        actualized:
          type: boolean
          description: Whether to include the transaction in budget actuals. Defaults to
            the workspace setting.
    TransactionPatch:
      type: object
      description: Fields to update on a transaction. Financial fields are editable
        only on manual transactions.
      additionalProperties: false
      minProperties: 1
      properties:
        projectId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
          description: Project ID or slug. Set to `null` to unassign the transaction.
        contactId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        budgetLineId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        fringeId:
          anyOf:
            - $ref: "#/components/schemas/Id"
            - type: "null"
        notes:
          type:
            - string
            - "null"
        number:
          type:
            - string
            - "null"
        ref:
          type:
            - string
            - "null"
        amount:
          $ref: "#/components/schemas/Money"
        timestamp:
          type: string
          format: date-time
          description: Transaction time. A date without a time is recorded at midnight UTC.
        type:
          $ref: "#/components/schemas/TransactionType"
        status:
          $ref: "#/components/schemas/TransactionStatus"
        description:
          type:
            - string
            - "null"
        merchant:
          type:
            - string
            - "null"
        sourceLast4:
          type:
            - string
            - "null"
        sourceName:
          type:
            - string
            - "null"
        actualized:
          type: boolean
          description: Whether the transaction is included in budget actuals.
    TransactionBulkCreate:
      type: object
      description: Up to 500 manual transactions to create in one request.
      additionalProperties: false
      required:
        - transactions
      properties:
        transactions:
          type: array
          minItems: 1
          maxItems: 500
          description: Manual transactions to create.
          items:
            $ref: "#/components/schemas/TransactionManualCreate"
    TransactionCollection:
      type: object
      description: A page of transactions.
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Transaction"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total number of matches. Included when `withCount=true`.
        truncated:
          type: boolean
          description: Whether the page contains fewer results than requested.
        statusReachability:
          $ref: "#/components/schemas/StatusReachabilityMatrix"
    TransactionItemCollection:
      type: object
      description: The itemized lines of a transaction.
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TransactionItem"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total number of matches. Included when `withCount=true`.
        truncated:
          type: boolean
          description: Whether the page contains fewer results than requested.
    TransactionStats:
      type: object
      description: Number and total amount of matching transactions.
      additionalProperties: false
      required:
        - total
        - amount
      properties:
        total:
          type: integer
          description: Number of matching transactions.
          examples:
            - 142
        amount:
          $ref: "#/components/schemas/Money"
    StatusReachabilityMatrix:
      type: object
      description: Transaction statuses available for each source.
      additionalProperties:
        type: array
        items:
          $ref: "#/components/schemas/TransactionStatus"
      examples:
        - manual:
            - posted
            - void
            - projected
          plaid:
            - pending
            - posted
            - void
            - needs_review
          saturation_pay:
            - unpaid
            - pending
            - posted
            - void
            - rejected
          saturation_credit:
            - pending
            - posted
            - void
            - needs_review
            - rejected
    WebhookEvent:
      type: string
      description: Event types available for webhook subscriptions.
      enum:
        - transaction.created
        - transaction.updated
        - budget.changed
        - purchaseOrder.created
        - purchaseOrder.pending
        - purchaseOrder.approved
        - purchaseOrder.rejected
        - purchaseOrder.actualizing
        - purchaseOrder.paid
        - purchaseOrder.void
        - document.created
        - document.linked
        - document.unlinked
        - document.deleted
        - incentive.added
        - pack.installed
        - pack.uninstalled
      examples:
        - transaction.created
    WebhookDeliveryEvent:
      type: string
      description: Event recorded for a delivery. `ping` is used by test deliveries.
      enum:
        - transaction.created
        - transaction.updated
        - budget.changed
        - purchaseOrder.created
        - purchaseOrder.pending
        - purchaseOrder.approved
        - purchaseOrder.rejected
        - purchaseOrder.actualizing
        - purchaseOrder.paid
        - purchaseOrder.void
        - document.created
        - document.linked
        - document.unlinked
        - document.deleted
        - incentive.added
        - pack.installed
        - pack.uninstalled
        - ping
    WebhookDeliveryStatus:
      type: string
      description: Outcome of a delivery. `pending` may be retried. `success`,
        `failed`, `blocked`, and `dropped` are final.
      enum:
        - pending
        - success
        - failed
        - blocked
        - dropped
    Webhook:
      type: object
      description: A webhook subscription for a workspace or project.
      additionalProperties: false
      required:
        - id
        - url
        - events
        - isActive
        - workspaceId
        - createdAt
        - updatedAt
      properties:
        id: &a57
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Subscription identifier (`whk_…`).
          examples:
            - whk_5c1a9e02
        url: &a58
          type: string
          format: uri
          description: HTTPS destination for deliveries. The host must resolve to a public
            address.
          examples:
            - https://hooks.example.com/saturation
        events: &a59
          type: array
          description: Event types delivered to this endpoint.
          minItems: 1
          items:
            $ref: "#/components/schemas/WebhookEvent"
        isActive: &a60
          type: boolean
          description: Whether the subscription currently receives deliveries. Toggled via
            PATCH; a webhook continues to exist while paused.
        workspaceId: &a61
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Workspace ID.
        projectId: &a62
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Project ID when the subscription is limited to one project.
        lastDeliveryAt: &a63
          type: string
          format: date-time
          description: Time of the most recent delivery attempt.
        lastDeliveryStatus: &a64
          allOf:
            - $ref: "#/components/schemas/WebhookDeliveryStatus"
          description: Outcome of the most recent delivery attempt.
        createdAt: &a65
          type: string
          format: date-time
          description: ISO-8601 creation timestamp.
        updatedAt: &a66
          type: string
          format: date-time
          description: ISO-8601 last-update timestamp.
    WebhookWithSecret:
      type: object
      description: A newly created webhook subscription and its signing secret.
      additionalProperties: false
      required:
        - id
        - url
        - events
        - isActive
        - workspaceId
        - createdAt
        - updatedAt
        - secret
      properties:
        id: *a57
        url: *a58
        events: *a59
        isActive: *a60
        workspaceId: *a61
        projectId: *a62
        lastDeliveryAt: *a63
        lastDeliveryStatus: *a64
        createdAt: *a65
        updatedAt: *a66
        secret:
          type: string
          description: HMAC secret used to verify `X-Saturation-Signature`. Returned only
            when the subscription is created.
          examples:
            - whsec_example
    WebhookCreate:
      type: object
      description: Fields for a new webhook subscription.
      additionalProperties: false
      required:
        - url
        - events
      properties:
        url:
          type: string
          format: uri
          description: HTTPS destination. The host must resolve to a public address.
          examples:
            - https://hooks.example.com/saturation
        events:
          type: array
          description: One or more event types to subscribe to.
          minItems: 1
          items:
            $ref: "#/components/schemas/WebhookEvent"
        secret:
          type: string
          description: Signing secret. When omitted, the create response includes a
            generated secret.
          minLength: 16
          maxLength: 256
        projectId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Project ID when the subscription should receive events for one
            project only.
    WebhookUpdate:
      type: object
      description: Writable webhook subscription fields.
      additionalProperties: false
      minProperties: 1
      properties:
        url:
          type: string
          format: uri
          description: New HTTPS destination. The host must resolve to a public address.
          examples:
            - https://hooks.example.com/saturation/v2
        events:
          type: array
          description: Replacement event set.
          minItems: 1
          items:
            $ref: "#/components/schemas/WebhookEvent"
        isActive:
          type: boolean
          description: Pause (`false`) or resume (`true`) deliveries.
    WebhookDelivery:
      type: object
      description: One webhook delivery and its retry state.
      additionalProperties: false
      required:
        - id
        - event
        - status
        - entityKind
        - entityId
        - attempts
        - occurredAt
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Delivery ID. It remains the same across retries.
          examples:
            - whd_9a02c1e5
        event:
          $ref: "#/components/schemas/WebhookDeliveryEvent"
        status:
          $ref: "#/components/schemas/WebhookDeliveryStatus"
        entityKind:
          type: string
          description: The kind of entity the event concerns (e.g. `transaction`,
            `budget`, `purchaseOrder`, `document`).
          examples:
            - transaction
        entityId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: ID of the resource that changed.
          examples:
            - txn_8f2a1c9e
        requestUrl:
          type: string
          format: uri
          description: URL used for the delivery.
          examples:
            - https://hooks.example.com/saturation
        responseStatus:
          type: integer
          description: HTTP status returned by the endpoint, when available.
          examples:
            - 200
        attempts:
          type: integer
          description: Number of delivery attempts.
          minimum: 1
          examples:
            - 1
        nextRetryAt:
          type: string
          format: date-time
          description: Time of the next retry. Present only while the delivery is pending.
        error:
          type: string
          description: Failure details when the delivery did not succeed.
        occurredAt:
          type: string
          format: date-time
          description: ISO-8601 timestamp of when the originating event occurred.
        deliveredAt:
          type: string
          format: date-time
          description: ISO-8601 timestamp of the terminal attempt. Absent while `pending`.
    WebhookEventPayload:
      type: object
      description: Webhook request body. Use `data` to fetch the current resource.
      additionalProperties: false
      required:
        - id
        - event
        - workspaceId
        - occurredAt
        - data
      properties:
        id:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Delivery ID for duplicate detection.
        event:
          $ref: "#/components/schemas/WebhookDeliveryEvent"
        workspaceId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: The workspace the event belongs to (`ws_…`).
        workspaceName:
          type: string
          description: Workspace name when available.
        projectId:
          allOf:
            - $ref: "#/components/schemas/Id"
          description: Project ID for project-scoped events.
        projectName:
          type: string
          description: Project name when available.
        occurredAt:
          type: string
          format: date-time
          description: ISO-8601 timestamp of the originating change.
        data:
          type: object
          description: The record to fetch.
          additionalProperties: false
          required:
            - kind
            - id
          properties:
            kind:
              type: string
              description: Type of resource that changed.
              examples:
                - transaction
            id:
              allOf:
                - $ref: "#/components/schemas/Id"
              description: ID of the resource that changed.
              examples:
                - txn_8f2a1c9e
    WebhookCollection:
      type: object
      description: A paginated page of webhook subscriptions.
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Webhook"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether inaccessible records shortened this page.
    WebhookDeliveryCollection:
      type: object
      description: A paginated page of delivery attempts for one subscription.
      additionalProperties: false
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDelivery"
        nextCursor:
          $ref: "#/components/schemas/NextCursor"
        count:
          type: integer
          description: Total matching items; present only when `withCount=true` was
            requested.
        truncated:
          type: boolean
          description: Whether inaccessible records shortened this page.
