> ## Documentation Index
> Fetch the complete documentation index at: https://developers.getbreezyapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Summarize full-job profitability for assigned members

> Same date, revenue, cost and eligibility basis as job profitability. Each distinct validated assigned company member receives the entire job result once across repeated appointments. Inactive members and canceled visits remain included; assignment does not prove attendance. Unassigned jobs have no member row. Member rows overlap and must not be summed as company totals. Rows order by period_start then member ID. This is participation, not sold/earned attribution or an allocation of profit.



## OpenAPI

````yaml /openapi.json get /reports/technician-participation-profitability
openapi: 3.0.3
info:
  title: Breezy Public Reporting API
  version: 1.0.0
  description: >-
    Read customers, team members, jobs, visits, assignments, installed
    equipment, captured form responses, time entries, configured-period
    timesheets, business reference catalogs, job leads, estimates, invoices,
    payments, refunds, recorded job financials, saved sold/earned credits, and
    financial summaries for your company. Existing API keys grant company-wide
    read access. Amounts are integer USD cents. Reads return current corrected
    records, with cursor pagination for collecting results.


    Read the [Breezy FSM guides](https://developers.getbreezyapp.com) for
    authentication, pagination, refresh limits, and business measures. All reads
    use latest corrected company records; cursors do not create a snapshot or a
    complete change feed.
servers:
  - url: https://api.getbreezyapp.com/v1
    description: Breezy FSM production API
security:
  - apiKey: []
tags:
  - name: Company
  - name: Invoices
  - name: Payments
  - name: Refunds
  - name: Reports
  - name: TeamMembers
  - name: Accounts
  - name: Contacts
  - name: Locations
  - name: Jobs
  - name: JobAppointments
  - name: JobAssignments
  - name: BusinessUnits
  - name: JobTypes
  - name: JobClasses
  - name: JobLifecycles
  - name: LeadSources
  - name: Tags
  - name: Estimates
  - name: JobLeads
  - name: Equipment
  - name: FormResponses
  - name: TimeEntries
  - name: Timesheets
  - name: JobFinancials
  - name: RevenueAttributions
externalDocs:
  description: Breezy FSM reporting guides and API reference
  url: https://developers.getbreezyapp.com
paths:
  /reports/technician-participation-profitability:
    get:
      tags:
        - Reports
      summary: Summarize full-job profitability for assigned members
      description: >-
        Same date, revenue, cost and eligibility basis as job profitability.
        Each distinct validated assigned company member receives the entire job
        result once across repeated appointments. Inactive members and canceled
        visits remain included; assignment does not prove attendance. Unassigned
        jobs have no member row. Member rows overlap and must not be summed as
        company totals. Rows order by period_start then member ID. This is
        participation, not sold/earned attribution or an allocation of profit.
      operationId: getTechnicianParticipationProfitability
      parameters:
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
            description: >-
              Maximum parent records or report rows. Complete children are
              always included.
          required: false
          description: >-
            Maximum parent records or report rows. Complete children are always
            included.
          name: limit
          in: query
        - schema:
            type: string
            nullable: true
            minLength: 1
            default: null
            description: >-
              Repeat the original filters; any valid page size may continue.
              Foreign-company, tampered or mismatched cursors return
              INVALID_CURSOR.
          required: false
          description: >-
            Repeat the original filters; any valid page size may continue.
            Foreign-company, tampered or mismatched cursors return
            INVALID_CURSOR.
          name: cursor
          in: query
        - schema:
            type: string
            format: date
            description: Inclusive company-local date.
          required: true
          description: Inclusive company-local date.
          name: start_date
          in: query
        - schema:
            type: string
            format: date
            description: Exclusive company-local date; must be after start_date.
          required: true
          description: Exclusive company-local date; must be after start_date.
          name: end_date
          in: query
        - schema:
            type: string
            enum:
              - day
              - week
              - month
              - quarter
              - year
            default: month
          required: false
          name: bucket
          in: query
        - schema:
            type: string
            nullable: true
            format: uuid
            default: null
          required: false
          name: account_id
          in: query
        - schema:
            type: string
            nullable: true
            format: uuid
            default: null
          required: false
          name: business_unit_id
          in: query
        - schema:
            type: string
            nullable: true
            format: uuid
            default: null
          required: false
          name: job_type_id
          in: query
        - schema:
            type: string
            nullable: true
            enum:
              - SERVICE
              - MAINTENANCE
              - ESTIMATE_REPAIR
              - ESTIMATE_REPLACE
              - INSTALL
              - WARRANTY
              - CALLBACK
              - SALES
              - UNKNOWN
              - null
          required: false
          name: job_class
          in: query
        - schema:
            type: string
            nullable: true
            format: uuid
            default: null
            description: >-
              A validated assigned member. Selects distinct jobs for job
              financials/profitability and only that member for the
              participation report.
          required: false
          description: >-
            A validated assigned member. Selects distinct jobs for job
            financials/profitability and only that member for the participation
            report.
          name: team_member_id
          in: query
        - schema:
            type: boolean
            default: true
          required: false
          name: verified_only
          in: query
        - schema:
            type: boolean
            default: false
            description: >-
              Include excluded or unavailable job-type mappings. Disabled
              costing and untracked jobs remain excluded.
          required: false
          description: >-
            Include excluded or unavailable job-type mappings. Disabled costing
            and untracked jobs remain excluded.
          name: include_excluded_job_types
          in: query
      responses:
        '200':
          description: Successful read. Clients ignore unrecognized response fields.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TechnicianParticipationResponse'
              example:
                data:
                  - period_start: '2026-08-01'
                    period_end: '2026-09-01'
                    currency: USD
                    group:
                      dimension: team_member
                      value: 11111111-1111-4111-8111-000000000401
                      label: Alex Example
                    job_count: 1
                    revenue_cents: 130000
                    labor_cost_cents: 6000
                    parts_cost_cents: 24000
                    equipment_cost_cents: 0
                    misc_cost_cents: 0
                    other_cost_cents: 0
                    total_cost_cents: 30000
                    gross_profit_cents: 100000
                    gross_margin: 0.7692
                pagination:
                  next_cursor: null
                meta:
                  request_id: 11111111-1111-4111-8111-000000009999
                  generated_at: '2026-09-08T19:00:00Z'
                  timezone: America/Los_Angeles
                report:
                  start_date: '2026-08-01'
                  end_date: '2026-10-01'
                  bucket: month
                  costing_enabled: true
                  verified_only: true
                  include_excluded_job_types: false
                  group_by: team_member
        '400':
          description: >-
            Malformed input, unknown query parameter, unsupported combination or
            invalid cursor.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: INVALID_REQUEST
                  message: end_date must be later than start_date
                  request_id: example-request
                  details: []
        '401':
          description: Missing, invalid or expired key, or invalid linked identity.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
            WWW-Authenticate:
              schema:
                type: string
              example: Bearer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: UNAUTHENTICATED
                  message: A valid API key is required
                  request_id: example-request
                  details: []
        '404':
          description: >-
            Missing resource or resource outside the authenticated company. Same
            response for both.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: NOT_FOUND
                  message: Resource not found
                  request_id: example-request
                  details: []
        '405':
          description: Write methods do not mutate business data and return 405.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
            Allow:
              schema:
                type: string
              example: GET, HEAD, OPTIONS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: METHOD_NOT_ALLOWED
                  message: This resource supports GET
                  request_id: example-request
                  details: []
        '429':
          description: Company request budget exhausted; retry after the indicated delay.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
            Retry-After:
              schema:
                type: integer
                minimum: 1
              description: Seconds before retrying.
              example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: RATE_LIMITED
                  message: Request limit exceeded
                  request_id: example-request
                  details: []
        '500':
          description: >-
            Unexpected failure. Share request_id with support; no stack or
            provider secrets in response.
          headers:
            Cache-Control:
              schema:
                type: string
              example: private, no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: INTERNAL_ERROR
                  message: Unable to complete request
                  request_id: example-request
                  details: []
      security:
        - apiKey: []
components:
  schemas:
    TechnicianParticipationResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TechnicianParticipationRow'
        pagination:
          $ref: '#/components/schemas/Pagination'
        meta:
          $ref: '#/components/schemas/ResponseMeta'
        report:
          type: object
          properties:
            start_date:
              type: string
              format: date
              description: Inclusive company-local date.
            end_date:
              type: string
              format: date
              description: Exclusive company-local date; must be after start_date.
            bucket:
              type: string
              enum:
                - day
                - week
                - month
                - quarter
                - year
              default: month
            costing_enabled:
              type: boolean
              description: >-
                False means this company has no enabled costing configuration;
                report rows are empty, not zero-valued profitability.
            verified_only:
              type: boolean
            include_excluded_job_types:
              type: boolean
            group_by:
              type: string
              enum:
                - team_member
          required:
            - start_date
            - end_date
            - costing_enabled
            - verified_only
            - include_excluded_job_types
            - group_by
      required:
        - data
        - pagination
        - meta
        - report
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - INVALID_REQUEST
                - INVALID_CURSOR
                - UNAUTHENTICATED
                - NOT_FOUND
                - METHOD_NOT_ALLOWED
                - RATE_LIMITED
                - INTERNAL_ERROR
            message:
              type: string
            request_id:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string
                required:
                  - field
                  - message
          required:
            - code
            - message
            - request_id
            - details
      required:
        - error
    TechnicianParticipationRow:
      type: object
      properties:
        period_start:
          type: string
          format: date
        period_end:
          type: string
          format: date
        currency:
          type: string
          enum:
            - USD
        group:
          type: object
          properties:
            dimension:
              type: string
              enum:
                - team_member
            value:
              type: string
              format: uuid
            label:
              type: string
          required:
            - dimension
            - value
            - label
        job_count:
          type: integer
          minimum: 0
        revenue_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
          description: >-
            Recorded pre-discount, pre-tax invoice subtotals in OPEN, PAID or
            UNCOLLECTABLE status.
        labor_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        parts_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        equipment_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        misc_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        other_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
          description: >-
            Recorded costs with an unrecognized category; retained in total
            costs.
        total_cost_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        gross_profit_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        gross_margin:
          type: number
          nullable: true
          description: >-
            Gross profit / revenue, rounded to four decimal places; null at zero
            revenue. A fraction, not a percentage.
      required:
        - period_start
        - period_end
        - currency
        - group
        - job_count
        - revenue_cents
        - labor_cost_cents
        - parts_cost_cents
        - equipment_cost_cents
        - misc_cost_cents
        - other_cost_cents
        - total_cost_cents
        - gross_profit_cents
        - gross_margin
      description: >-
        Each distinct assigned member receives the whole included job result
        once. Member rows overlap; do not sum them as company totals. Jobs
        without participants have no member row.
    Pagination:
      type: object
      properties:
        next_cursor:
          type: string
          nullable: true
          description: >-
            Opaque continuation. Null ends traversal. Keep the same filters;
            page size may change.
      required:
        - next_cursor
    ResponseMeta:
      type: object
      properties:
        request_id:
          type: string
        generated_at:
          type: string
          format: date-time
        timezone:
          type: string
      required:
        - request_id
        - generated_at
        - timezone
      description: >-
        Generation time and company timezone. generated_at is not a snapshot or
        synchronization token.
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        Existing Breezy API key. Grants all published reads in its associated
        company. No app permission scopes.

````