> ## 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 recorded job profitability

> Enabled costing and TRACKED jobs only; defaults to VERIFIED jobs and included owned job types. Revenue is recorded OPEN/PAID/UNCOLLECTABLE pre-discount, pre-tax invoice subtotals. Whole-job date is earliest qualifying invoice issue time, then work completion, then job creation, in company timezone. One optional business grouping plus time; null business groups retained when eligible. Rows order by period_start then group value, null first. Empty buckets omitted. Margin is calculated from summed amounts, not averaged job margins.



## OpenAPI

````yaml /openapi.json get /reports/job-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/job-profitability:
    get:
      tags:
        - Reports
      summary: Summarize recorded job profitability
      description: >-
        Enabled costing and TRACKED jobs only; defaults to VERIFIED jobs and
        included owned job types. Revenue is recorded OPEN/PAID/UNCOLLECTABLE
        pre-discount, pre-tax invoice subtotals. Whole-job date is earliest
        qualifying invoice issue time, then work completion, then job creation,
        in company timezone. One optional business grouping plus time; null
        business groups retained when eligible. Rows order by period_start then
        group value, null first. Empty buckets omitted. Margin is calculated
        from summed amounts, not averaged job margins.
      operationId: getJobProfitability
      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
            enum:
              - business_unit
              - job_type
              - job_class
              - null
          required: false
          name: group_by
          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/JobProfitabilityResponse'
              example:
                data:
                  - period_start: '2026-08-01'
                    period_end: '2026-09-01'
                    currency: USD
                    group: null
                    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: null
        '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:
    JobProfitabilityResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/JobProfitabilityRow'
        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
              nullable: true
              enum:
                - business_unit
                - job_type
                - job_class
                - null
          required:
            - start_date
            - end_date
            - costing_enabled
            - verified_only
            - include_excluded_job_types
      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
    JobProfitabilityRow:
      type: object
      properties:
        period_start:
          type: string
          format: date
        period_end:
          type: string
          format: date
        currency:
          type: string
          enum:
            - USD
        group:
          type: object
          nullable: true
          properties:
            dimension:
              type: string
              enum:
                - business_unit
                - job_type
                - job_class
            value:
              type: string
              nullable: true
            label:
              type: string
              nullable: true
          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
    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.

````