# Page accounts Source: https://breezy-fsm.mintlify.app/api-reference/accounts/page-accounts /openapi.json get /accounts Customers with complete contact/location associations, tags, and recorded acquisition sources. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one account Source: https://breezy-fsm.mintlify.app/api-reference/accounts/read-one-account /openapi.json get /accounts/{id} Customers with complete contact/location associations, tags, and recorded acquisition sources. # Page business units Source: https://breezy-fsm.mintlify.app/api-reference/businessunits/page-business-units /openapi.json get /business-units Company business units for joining and segmenting operational records. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one business unit Source: https://breezy-fsm.mintlify.app/api-reference/businessunits/read-one-business-unit /openapi.json get /business-units/{id} Company business units for joining and segmenting operational records. # Read the company associated with this key Source: https://breezy-fsm.mintlify.app/api-reference/company/read-the-company-associated-with-this-key /openapi.json get /company Read only within the company associated with the validated key. # Page contacts Source: https://breezy-fsm.mintlify.app/api-reference/contacts/page-contacts /openapi.json get /contacts People and communication channels with complete account-specific primary and archive state. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one contact Source: https://breezy-fsm.mintlify.app/api-reference/contacts/read-one-contact /openapi.json get /contacts/{id} People and communication channels with complete account-specific primary and archive state. # Page equipment Source: https://breezy-fsm.mintlify.app/api-reference/equipment/page-equipment /openapi.json get /equipment Installed items at owned locations, with recorded condition, lifecycle dates, warranty terms, and optional same-location HVAC grouping. All operational statuses are included by default. No inferred age, warranty eligibility, or item service history. Orders by id ascending. List and detail return the same complete representation. updated_since covers parent-row saves only. # Read one equipment Source: https://breezy-fsm.mintlify.app/api-reference/equipment/read-one-equipment /openapi.json get /equipment/{id} Installed items at owned locations, with recorded condition, lifecycle dates, warranty terms, and optional same-location HVAC grouping. All operational statuses are included by default. No inferred age, warranty eligibility, or item service history. # Page estimates Source: https://breezy-fsm.mintlify.app/api-reference/estimates/page-estimates /openapi.json get /estimates Proposals with complete options, lines, discounts, recorded totals, selection, current acceptance/loss information, and all resulting invoice IDs. Alternatives are not additive estimate value. Orders by created_at then id ascending. All statuses and complete embedded children are included by default. # Read one estimate Source: https://breezy-fsm.mintlify.app/api-reference/estimates/read-one-estimate /openapi.json get /estimates/{id} Proposals with complete options, lines, discounts, recorded totals, selection, current acceptance/loss information, and all resulting invoice IDs. Alternatives are not additive estimate value. # Page form responses Source: https://breezy-fsm.mintlify.app/api-reference/formresponses/page-form-responses /openapi.json get /form-responses Captured visit forms with complete questions, recorded answers, original work relationships, and current required-data completeness. Current templates do not replace captured content. Unsupported capture returns null questions and completeness while retaining safe metadata. Orders by id ascending. List and detail return the same complete representation. updated_since covers parent-row saves only. # Read one form response Source: https://breezy-fsm.mintlify.app/api-reference/formresponses/read-one-form-response /openapi.json get /form-responses/{id} Captured visit forms with complete questions, recorded answers, original work relationships, and current required-data completeness. Current templates do not replace captured content. Unsupported capture returns null questions and completeness while retaining safe metadata. # Page complete invoices Source: https://breezy-fsm.mintlify.app/api-reference/invoices/page-complete-invoices /openapi.json get /invoices All statuses by default. Orders by created_at then id ascending. Lines, discounts and payment applications are complete on every page. Amounts use the public invoice calculator; refunds are not inferred as invoice-level allocations. # Read one complete invoice Source: https://breezy-fsm.mintlify.app/api-reference/invoices/read-one-complete-invoice /openapi.json get /invoices/{invoice_id} Read only within the company associated with the validated key. # Page job appointments Source: https://breezy-fsm.mintlify.app/api-reference/jobappointments/page-job-appointments /openapi.json get /job-appointments Customer visit windows with confirmation and cancellation state. One appointment is one visit, regardless of its technician count. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one job appointment Source: https://breezy-fsm.mintlify.app/api-reference/jobappointments/read-one-job-appointment /openapi.json get /job-appointments/{id} Customer visit windows with confirmation and cancellation state. One appointment is one visit, regardless of its technician count. # Page job assignments Source: https://breezy-fsm.mintlify.app/api-reference/jobassignments/page-job-assignments /openapi.json get /job-assignments A member assignment to a visit, including its scheduled span and recorded execution status. This does not establish attendance or actual hours worked. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one job assignment Source: https://breezy-fsm.mintlify.app/api-reference/jobassignments/read-one-job-assignment /openapi.json get /job-assignments/{id} A member assignment to a visit, including its scheduled span and recorded execution status. This does not establish attendance or actual hours worked. # Page job classes Source: https://breezy-fsm.mintlify.app/api-reference/jobclasses/page-job-classes /openapi.json get /job-classes Existing job-class codes and display names, including legacy classes. IDs are class codes. Orders by id ascending; no timestamps or update filter. # Read one job class Source: https://breezy-fsm.mintlify.app/api-reference/jobclasses/read-one-job-class /openapi.json get /job-classes/{id} Existing job-class codes and display names, including legacy classes. IDs are class codes. Orders by id ascending; no timestamps or update filter. # Page jobs with recorded costs and costing revenue Source: https://breezy-fsm.mintlify.app/api-reference/jobfinancials/page-jobs-with-recorded-costs-and-costing-revenue /openapi.json get /job-financials One resource per owned job, identified by job ID and ordered by ID ascending. Complete saved costs, qualifying invoice facts and distinct assigned company members. Disabled or untracked costing has null totals while saved facts remain readable. Date filters refer to job creation or the company-local financial report date. No financial updated_since or snapshot. # Read the recorded financials of one job Source: https://breezy-fsm.mintlify.app/api-reference/jobfinancials/read-the-recorded-financials-of-one-job /openapi.json get /job-financials/{id} The same complete representation as collection pages, using the job ID. Reads saved costs without populating or synchronizing them from timekeeping, wages, invoices or pricebook data. # Page job leads Source: https://breezy-fsm.mintlify.app/api-reference/jobleads/page-job-leads /openapi.json get /job-leads Submitted service requests with captured contact/address, free-form intake source, and recorded conversion state. A converted lead is not evidence of a sale; multiple leads can refer to one job. Orders by created_at then id ascending. All statuses and complete embedded children are included by default. # Read one job lead Source: https://breezy-fsm.mintlify.app/api-reference/jobleads/read-one-job-lead /openapi.json get /job-leads/{id} Submitted service requests with captured contact/address, free-form intake source, and recorded conversion state. A converted lead is not evidence of a sale; multiple leads can refer to one job. # Page job lifecycles Source: https://breezy-fsm.mintlify.app/api-reference/joblifecycles/page-job-lifecycles /openapi.json get /job-lifecycles Configured lifecycles, including archived lifecycles, with complete ordered statuses and their stage and special-status meaning. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one job lifecycle Source: https://breezy-fsm.mintlify.app/api-reference/joblifecycles/read-one-job-lifecycle /openapi.json get /job-lifecycles/{id} Configured lifecycles, including archived lifecycles, with complete ordered statuses and their stage and special-status meaning. # Page jobs Source: https://breezy-fsm.mintlify.app/api-reference/jobs/page-jobs /openapi.json get /jobs Work and opportunities with current lifecycle status, recorded dimensions, and distinct work-completion and lifecycle-closure dates. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one job Source: https://breezy-fsm.mintlify.app/api-reference/jobs/read-one-job /openapi.json get /jobs/{id} Work and opportunities with current lifecycle status, recorded dimensions, and distinct work-completion and lifecycle-closure dates. # Page job types Source: https://breezy-fsm.mintlify.app/api-reference/jobtypes/page-job-types /openapi.json get /job-types Configured job types, including archived types, with their class, lifecycle, and default business unit. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one job type Source: https://breezy-fsm.mintlify.app/api-reference/jobtypes/read-one-job-type /openapi.json get /job-types/{id} Configured job types, including archived types, with their class, lifecycle, and default business unit. # Page lead sources Source: https://breezy-fsm.mintlify.app/api-reference/leadsources/page-lead-sources /openapi.json get /lead-sources Configured company source names and canonical identity, including archived sources. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one lead source Source: https://breezy-fsm.mintlify.app/api-reference/leadsources/read-one-lead-source /openapi.json get /lead-sources/{id} Configured company source names and canonical identity, including archived sources. # Page locations Source: https://breezy-fsm.mintlify.app/api-reference/locations/page-locations /openapi.json get /locations Service places with addresses, property information, and complete account associations. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one location Source: https://breezy-fsm.mintlify.app/api-reference/locations/read-one-location /openapi.json get /locations/{id} Service places with addresses, property information, and complete account associations. # Page payments with their invoice allocations Source: https://breezy-fsm.mintlify.app/api-reference/payments/page-payments-with-their-invoice-allocations /openapi.json get /payments All statuses by default. Orders by created_at then id ascending. A payment amount is counted once regardless of its invoice allocations. # Read one payment Source: https://breezy-fsm.mintlify.app/api-reference/payments/read-one-payment /openapi.json get /payments/{payment_id} Read only within the company associated with the validated key. # Page refunds using their own occurrence dates Source: https://breezy-fsm.mintlify.app/api-reference/refunds/page-refunds-using-their-own-occurrence-dates /openapi.json get /refunds All statuses by default. Orders by created_at then id ascending. Date filters refer to this refund, even if its payment occurred in an earlier period. # Read one refund Source: https://breezy-fsm.mintlify.app/api-reference/refunds/read-one-refund /openapi.json get /refunds/{refund_id} Read only within the company associated with the validated key. # Read current account aging Source: https://breezy-fsm.mintlify.app/api-reference/reports/read-current-account-aging /openapi.json get /reports/receivables-aging OPEN invoices only, including zero/negative balances. Group by account ID ascending. Signed buckets sum to balance_cents. Aging uses current company-local date; no as_of or historical date range. Accounts without qualifying OPEN invoices are omitted. Drill down with the identical filters on GET /invoices?status=OPEN. # Summarize full-job profitability for assigned members Source: https://breezy-fsm.mintlify.app/api-reference/reports/summarize-full-job-profitability-for-assigned-members /openapi.json get /reports/technician-participation-profitability 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. # Summarize invoice activity by issue date Source: https://breezy-fsm.mintlify.app/api-reference/reports/summarize-invoice-activity-by-issue-date /openapi.json get /reports/invoice-activity Defaults to OPEN and PAID invoices whose issued_at falls within the company-local date range. Sum public invoice amounts. One optional business grouping plus time. Null issue dates are excluded. Rows order by period_start then group value (null first); empty groups/buckets are omitted. # Summarize recorded job profitability Source: https://breezy-fsm.mintlify.app/api-reference/reports/summarize-recorded-job-profitability /openapi.json get /reports/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. # Summarize recorded sold and earned credits by member Source: https://breezy-fsm.mintlify.app/api-reference/reports/summarize-recorded-sold-and-earned-credits-by-member /openapi.json get /reports/revenue-attribution Company-local work-completion date with no fallback. Fixed credited-member grouping; unavailable members share a null group. Separate saved sold/earned cents and credit counts, plus distinct contributing job count. Filters select credits. No invoice-payment, assignment or costing eligibility requirement. Member credits overlap; sold and earned are separate measures, not additive company revenue. Rows order by period_start then member ID, null first; empty buckets omitted and periods clipped to the request. # Summarize successful payments and refunds Source: https://breezy-fsm.mintlify.app/api-reference/reports/summarize-successful-payments-and-refunds /openapi.json get /reports/collections PAID payments minus SUCCEEDED refunds; each uses its own occurrence date and is counted once. No proportional refund allocation to invoices, jobs or business units. One optional grouping plus time; rows order by period_start then group value (null first). Empty groups/buckets are omitted. # Page jobs with complete saved sold and earned credits Source: https://breezy-fsm.mintlify.app/api-reference/revenueattributions/page-jobs-with-complete-saved-sold-and-earned-credits /openapi.json get /revenue-attributions One resource per owned job, including empty credit arrays and undated jobs. Orders by job ID ascending. Member and credit-type filters must match the same credit to select a job; the returned array stays complete. Amounts preserve explicit recorded credits, including zero and negative values. No inferred attribution, save timestamp or updated_since. # Read the complete saved revenue credits of one job Source: https://breezy-fsm.mintlify.app/api-reference/revenueattributions/read-the-complete-saved-revenue-credits-of-one-job /openapi.json get /revenue-attributions/{id} Uses the job ID and returns the same complete representation as collection pages. Replace the entire credit array when refreshing. Unavailable current references remain null or empty while owned credit amounts remain readable. Matching invoice lines provide context only; several may match one saved credit. # Page tags Source: https://breezy-fsm.mintlify.app/api-reference/tags/page-tags /openapi.json get /tags Company tags used to label customers and jobs. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one tag Source: https://breezy-fsm.mintlify.app/api-reference/tags/read-one-tag /openapi.json get /tags/{id} Company tags used to label customers and jobs. # Page team members Source: https://breezy-fsm.mintlify.app/api-reference/teammembers/page-team-members /openapi.json get /team-members Company members, including inactive members, with business roles and dated business-unit assignments. Orders by created_at then id ascending. Complete embedded relationships are returned on every page. # Read one team member Source: https://breezy-fsm.mintlify.app/api-reference/teammembers/read-one-team-member /openapi.json get /team-members/{id} Company members, including inactive members, with business roles and dated business-unit assignments. # Page recorded time entries Source: https://breezy-fsm.mintlify.app/api-reference/timeentries/page-recorded-time-entries /openapi.json get /time-entries Effective corrected intervals, including custom activities and validated work links. Orders by created_at then id ascending. Soft-deleted entries require include_deleted=true. No reliable updated_since filter; refresh known IDs and effective-start windows. Elapsed duration is distinct from capped timesheet minutes. # Read one time entry Source: https://breezy-fsm.mintlify.app/api-reference/timeentries/read-one-time-entry /openapi.json get /time-entries/{id} The same representation as collection pages. Retained soft-deleted entries require include_deleted=true. # Page members in a configured timesheet period Source: https://breezy-fsm.mintlify.app/api-reference/timesheets/page-members-in-a-configured-timesheet-period /openapi.json get /timesheets Required period_date selects a current configured company-local period. All current company members, including inactive and zero-entry members, ordered by member ID. Effective-start-in-period entries contribute; open, deleted, nonpayable and unknown-activity entries do not contribute payable minutes. Existing server timesheet rules use wall-clock minutes, cap days at 1439, and stop overnight spans at the end of their starting day. No payroll or costing calculation. Current configuration applies to historical dates. Cursor scope includes resolved boundaries. # Read one member’s configured-period timesheet Source: https://breezy-fsm.mintlify.app/api-reference/timesheets/read-one-member’s-configured-period-timesheet /openapi.json get /timesheets/{team_member_id} Derived representation identified by team member and resolved period dates. Required period_date is a local calendar date. Includes a zero total when the member has no entries. Returns 400 for missing or unusable configuration and 404 for a missing or foreign member. # Authentication Source: https://breezy-fsm.mintlify.app/authentication Use one API key for read-only access to its company. Send `Authorization: Bearer YOUR_API_KEY` and `Accept: application/json`. Your key grants every published read in its associated company. There are no permission scopes or client-selected company IDs. `GET /company` returns the company, currency, and timezone. A valid key cannot read another company's records; a detail ID outside your company returns the same 404 as a missing record. ## Get and use a key Breezy issues company API keys. Ask your Breezy contact to issue or replace yours. Use HTTPS and send the key in the `Authorization` header. Keep it in your reporting service’s secret storage or environment; do not put it in URLs, source control, shared prompts, or browser applications you distribute to other users. ```http theme={null} GET /v1/company HTTP/1.1 Host: api.getbreezyapp.com Authorization: Bearer YOUR_API_KEY Accept: application/json ``` ## Access and lifecycle Every published business endpoint is a GET. A key grants all of these reads for its associated company, including financial data. Team-member roles do not narrow that access. An invalid or expired key, or an inactive or mismatched linked identity, returns 401. ## Try a request The API reference offers an interactive request panel. Requests go directly from your browser to `api.getbreezyapp.com`; browser cookies are not used for authentication. Documentation and the OpenAPI specification are public and require no key. For automated collection, use a server-side client or a trusted local tool. See [Errors and rate limits](/errors) for retries. # Choose your reporting data Source: https://breezy-fsm.mintlify.app/choose-your-data Map business questions to resources, summaries, and the right row grain. Use detailed resources to build your own reporting store and summaries for the API’s supported financial groupings. The same records can answer different questions depending on the date and amount basis you choose. | Business question | Start with | Read next | | ----------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------- | | How much work did we complete? | Jobs, appointments, assignments | [Work and customers](/work-and-customers) | | What did we bill, collect, or remain owed? | Invoice activity, collections, receivables aging | [Revenue, collections, and AR](/financial-reporting) | | Which members participated in profitable work? | Technician participation profitability | [Technician performance](/technician-performance) | | Who has recorded sold or earned credit? | Revenue attributions | [Technician performance](/technician-performance) | | What is our current lead and proposal pipeline? | Job leads and estimates | [Leads and estimates](/leads-and-estimates) | | What time was recorded and payable? | Time entries and timesheets | [Time reporting](/time-reporting) | | What equipment and captured forms do we have? | Equipment and form responses | [Equipment and forms](/equipment-and-forms) | ## Available reads Available reads cover company context, operational records and reference catalogs, installed equipment, captured form responses, job leads, complete estimates, time entries, configured-period timesheets, invoice/payment/refund details, recorded job financials, saved revenue attribution, and six financial summaries. | Read | Use | | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | | `GET /company` | Identify the company and reporting timezone. | | `GET /job-leads` and `/job-leads/{id}` | Read submitted requests, captured contact/address values, intake source text, and recorded conversion links. | | `GET /estimates` and `/estimates/{id}` | Read proposals with complete options, lines, discounts, recorded totals, acceptance state, and resulting invoice IDs. | | `GET /equipment` and `/equipment/{id}` | Read installed items, recorded condition/lifecycle/warranty information, and location/HVAC-system grouping. | | `GET /form-responses` and `/form-responses/{id}` | Read captured visit questions and answers, including incomplete forms, with original job/appointment relationships. | | `GET /time-entries` and `/time-entries/{id}` | Read effective corrected work intervals, activity/payable state, elapsed minutes, and work/member links. | | `GET /timesheets?period_date=...` and `/timesheets/{team_member_id}?period_date=...` | Read current configured-period payable totals and complete daily values for every company member. | | `GET /invoices` and `/invoices/{invoice_id}` | Read invoices with complete lines, discounts, tax, amounts, and payment applications. | | `GET /payments` and `/payments/{payment_id}` | Read each payment once with all amounts allocated to invoices. | | `GET /refunds` and `/refunds/{refund_id}` | Read refunds independently using their own dates. | | `GET /reports/invoice-activity` | Sum issued invoice activity by period and an optional business dimension. | | `GET /reports/collections` | Sum received payments and successful refunds by their occurrence dates. | | `GET /reports/receivables-aging` | Read current signed account balances and aging buckets. | | `GET /revenue-attributions` and `/revenue-attributions/{id}` | Read each job’s complete saved sold and earned credits, including empty arrays. | | `GET /reports/revenue-attribution` | Read separate saved sold/earned amounts and counts by credited member and work-completion date. | | `GET /job-financials` and `/job-financials/{id}` | Read complete saved costs, costing revenue, current costing state and participants using the job ID. | | `GET /reports/job-profitability` | Sum recorded job revenue, costs and gross profit by the costing report date and optional business dimension. | | `GET /reports/technician-participation-profitability` | Read each assigned member's full-job participation totals; member rows overlap. | Operational collections also have a detail read at the collection path followed by `/{id}`. | Operational collection | Business meaning and additional filters | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/team-members` | Current company membership, identity, business roles, active state, and dated business-unit assignments. Filter `role` and `active`. | | `/accounts` | Customers, recorded `customer_since`, mailing address, manager, service restriction, complete contact/location associations, tags, and acquisition sources. Filter `type`, `archived`, `contact_id`, and `location_id`. | | `/contacts` | People with recorded email/phone channels and complete account associations. Filter `account_id`. | | `/locations` | Service places, address and property data, and complete account associations. Filter `account_id` and exact `property_type`. | | `/jobs` | Work and opportunities with dimensions, current lifecycle/status, outcomes, creator, tags, sources, and separate completion/closure times. Filter `account_id`, `location_id`, `business_unit_id`, `job_type_id`, `job_class`, `status_id`, `stage`, `created_by_id`, and `team_member_id`. | | `/job-appointments` | Visit windows, recorded creator, confirmation, and cancellation. Filter `job_id`, `created_by_id`, `confirmed`, and `canceled`. | | `/job-assignments` | A member assigned to a visit, scheduled span, and execution status. Filter `job_id`, `appointment_id`, `team_member_id`, and repeated `status`. | | `/business-units` | Company units for segmentation. | | `/job-types` | Configured job types, class, lifecycle, default business unit, duration, and opportunity flag. Filter `archived`, `job_class`, and `lifecycle_id`. | | `/job-classes` | Existing class codes and display names. Only `ids`, `limit`, and `cursor` filters. | | `/job-lifecycles` | Configured workflows and their complete ordered statuses. Filter `archived`. | | `/lead-sources` | Configured company source names and their canonical source identity. Filter `archived`. | | `/tags` | Company labels used on accounts and jobs. | # Dates, money, and identities Source: https://breezy-fsm.mintlify.app/conventions Interpret local calendar dates, timestamp precision, cents, nulls, and reporting buckets. ## Identities and missing values Resources use UUID `id` values for joins (job-class IDs are their uppercase codes) and human-readable `number` or `name` values for display. Optional relationships are explicitly null. Embedded references include names for display without a separate lookup. Invoice lines have IDs; an allocation's identity is its payment/invoice pair. A derived timesheet is identified by member ID and resolved period dates, with no persisted ID. Clients should preserve these identities and ignore unrecognized response fields. Enum values and meanings are documented in the schemas. `job_class` preserves the recorded uppercase value, including legacy classes: `SERVICE`, `MAINTENANCE`, `ESTIMATE_REPAIR`, `ESTIMATE_REPLACE`, `INSTALL`, `WARRANTY`, `CALLBACK`, `SALES`, and `UNKNOWN`. It is not a broader reporting class group. A missing relationship produces null; the recorded value `UNKNOWN` remains a distinct value. ## Money All amounts ending in `_cents` are integer USD cents. Rates are fractions: `0.1` means 10%. Preserve signed amounts, including credits and negative balances. A null value is unavailable or inapplicable according to its field definition; do not automatically turn it into zero. ## Calendar dates and timestamps Dates use years `0001` through `9999` and must be valid calendar dates. Timestamp inputs must represent valid calendar instants and include `Z` or a UTC offset between `-15:59` and `+15:59`; examples use `Z`. Percent-encode a positive offset's `+` when placing it in a query string. Original microsecond precision is retained in timestamp filters, resource timestamps, and cursors. The request's company timezone determines calendar date filters, report buckets, and aging. Calendar ranges include each local day in full, even when clocks change at midnight. For September in the company’s timezone, use `start_date=2026-09-01&end_date=2026-10-01`. This includes September 30 and excludes October 1. Timestamp filters such as `created_from` instead need an offset, for example `2026-09-01T07:00:00Z` for midnight in Los Angeles on that date. ## Summary periods and segmentation Date-based summaries require `start_date` and `end_date`, with an inclusive start and exclusive end. They support `day`, Monday-start `week`, calendar `month`, `quarter`, and `year`; the default is month. At most one `group_by` dimension is allowed alongside time. Business filters can be combined without adding groupings. Summary rows contain the effective half-open `period_start`/`period_end`, clipped to the requested range at its edges. Invoice activity uses issue date; collections use each payment/refund occurrence date. Rows order by period start then group value, with null group values first. There is no zero-filling of absent periods or groups. An ungrouped row has `group: null`; an unknown business unit has a group object with a null value and label. `data` is pageable and contains no hidden grand-total row. Sum additive amounts/counts across returned rows; calculate an overall average from total amount and count, not an average of averages. All pages must succeed before using the result as complete. Each report documents its own supported dimensions. For additional combinations, accumulate the detailed resources and group them in your reporting store. The API does not accept arbitrary SQL, grouping lists, or invented filters. # Equipment and captured forms Source: https://breezy-fsm.mintlify.app/equipment-and-forms Read installed items and complete captured questions and answers. ## Installed equipment Installed equipment is available at `/equipment`. Each item belongs to a location and may reference an HVAC system at that same location. Use `location_id` to join `/locations` and its complete account associations. Equipment's `account_id` filter includes archived location/account associations as well as current ones. All operational statuses are returned by default, including deactivated items. Exact filters include location, HVAC system, equipment type, manufacturer, condition, and repeated status values. Recorded legacy or custom classification strings remain available. ```sh theme={null} curl "https://api.getbreezyapp.com/v1/equipment?status=IN_SERVICE&condition=FAIR&limit=100" \ -H "Authorization: Bearer $BREEZY_API_KEY" curl "https://api.getbreezyapp.com/v1/form-responses?updated_since=2026-09-01T00:00:00Z&limit=50" \ -H "Authorization: Bearer $BREEZY_API_KEY" ``` Equipment lifecycle and warranty dates are recorded calendar dates. They do not establish calculated age, replacement probability, current warranty eligibility, or equipment-specific service history. Duplicate serial numbers do not make two records the same item. The API preserves nullable legacy creation/update timestamps; it does not substitute another date. Form responses include complete recorded answers, including signature data URIs, so page size bounds parent count rather than response bytes. For forms with large media strings or many questions, start with `limit=10` and lower it if needed; children are never silently truncated. Both equipment and form-response collections order by immutable ID ascending. Creation bounds exclude unavailable creation dates. Follow `next_cursor` with the same filters, changing page size as needed. ## Form instances and relationships Form responses contain a captured name, instance number/label, ad-hoc state, and the complete question/answer set from the original appointment. Follow-up jobs can reuse a response in the app; the API returns that instance once with its original `job_id` and `appointment_id`. `form_id` identifies the source form for grouping. Current template edits do not replace captured questions or names. Filters include original job/appointment, account/location, source form, business unit, job type/class, last saver, and ad-hoc state. Use `/jobs` and `/team-members` to join work dimensions and recorded savers. ## Questions and answers Questions retain captured labels, types, required/photo requirements, helper text, and section context. Dual-column inputs are interleaved by row in display order. `question_id` is nullable for legacy content and is not guaranteed stable across revisions. `answer_path` is local to the captured instance, such as `/items/2/right/0/response`; it changes if the captured structure is reordered. Replace the complete question set when refreshing an instance, rather than treating question labels or paths as global IDs. Every answer is a string or null. `No`, `false`, `0`, and the empty string remain distinct from an absent answer. Rich-text TEXT values become plain text; other types retain the recorded string. PHOTO normally contains a CDN URL and SIGNATURE normally contains a PNG data URI. An associated photo is a separate recorded string. These are captured values, not verified attachment references or newly signed links; the API does not fetch media. If a captured structure is unsupported or malformed, `questions` and `completed` are null together while safe instance metadata remains available. Null questions mean unavailable content, not an empty form. ## Completion semantics `completed` follows the existing required-answer and required-photo check on the original capture, before TEXT conversion. It is not a recorded submission, approval, completion event, or verified signature. Empty/title-only/optional-only forms may be complete. Whitespace and HTML-only strings follow the app's existing presence rules. Required associated photos matter even for optional answers; PHOTO inputs use their own value. Customers can segment this response value locally; there is no completion filter or invented completion timestamp. ## Refreshes and deletions For both collections, `updated_since` covers parent-row saves only. Equipment can change through its related system/location/account data without its own timestamp advancing. A form's last editor and update timestamp mean last save: the app can save several instances together when only one changed. Parent work dimensions and template edits do not become form save events. Refresh known IDs or broader scopes when those relationships matter. Both resources can be hard-deleted and provide no tombstone or guaranteed deletion feed. Collection and detail representations are identical, including complete questions/media; smaller parent-page limits help with large captured forms. # Errors and rate limits Source: https://breezy-fsm.mintlify.app/errors Handle validation failures, throttling, and retries without losing fetched pages. Errors use `error.code`, a readable `message`, `request_id`, and field-level `details` when applicable. No stack traces or provider payloads are part of an error. The default rate budget is 60 requests per minute per company, shared across keys and server instances. A throttled request returns 429 with `Retry-After`; retain already fetched pages and retry the same cursor after that interval. | Status | Client action | | ------ | ---------------------------------------------------------------------------------------------- | | 400 | Correct invalid input or restart with the original query if the cursor is invalid. | | 401 | Supply a valid key. Expired keys or inactive/mismatched linked identities cannot authenticate. | | 404 | The detail resource is unavailable within this company. | | 405 | Use GET; write methods are unsupported. | | 429 | Wait the `Retry-After` seconds, then retry the same request with backoff. | | 500 | Retry with bounded backoff; share `request_id` with support if it persists. | ## Retry without duplicating records For 429, wait at least `Retry-After` seconds. For a transient 500 or network failure, use bounded exponential backoff and retry the same request. Keep already fetched pages and upsert records by their documented identities. If retries are exhausted, record the unfinished query and cursor so you can resume it. A financial result outside the supported integer range also returns 500. Repeating that unchanged query cannot recover it: narrow the scope where possible or contact support with the request ID. See [Job profitability](/job-profitability). ## Diagnose a rejected query A 400 is not a retry signal. Check required dates, supported filters, repeated scalar parameters, and whether your cursor belongs to this company, endpoint, and filter set. Restart without a cursor if you intentionally change the query. A 404 does not distinguish an unknown ID from a record outside your company. # Revenue, collections, and AR Source: https://breezy-fsm.mintlify.app/financial-reporting Keep issued invoice activity, received cash, and current receivables distinct. | Measure | Basis | Date | | ----------------- | --------------------------------------------------------- | ----------------------------------------- | | Invoice activity | Calculated invoice values; defaults to OPEN and PAID | Invoice issue date | | Collections | Payments currently PAID minus refunds currently SUCCEEDED | Each payment/refund occurrence date | | Receivables aging | Current signed balance of OPEN invoices | Current company-local date | | Job profitability | Recorded costing subtotal minus saved costs | [Costing report date](/job-profitability) | ## Start with a summary ```http theme={null} GET /v1/reports/invoice-activity?start_date=2026-08-01&end_date=2026-10-01&bucket=month GET /v1/reports/collections?start_date=2026-09-01&end_date=2026-10-01&bucket=month GET /v1/reports/receivables-aging ``` Use [Dates, money, and identities](/conventions) for time buckets, grouping, and total calculations. All summaries are pageable. ## Worked example | Example measure | Expected amount | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | Invoice 1001 | $1,000 subtotal − $100 discount + $90 tax = $990 total. | | Its current open balance | $990 − $500 paid applications − $100 processing applications = $390. | | Payment P-1001 | $800 received once: $500 applied to invoice 1001, \$300 to invoice 1002. | | September collections | $800 received − $50 successful refund = $750. The $100 processing payment and \$20 pending refund do not enter collections. | | Invoice activity | August: one invoice, $990 total. September: two invoices, $500 total and \$250 average. | | Current AR on September 8 | $590: $390 in 1–30 days overdue plus invoice 1003's \$200 due September 30 in current. Invoice 1002 is paid and excluded. | These dates and amounts describe the fictional example dataset. Live receivables aging always uses the current company-local date. ## Invoice amount basis Invoice totals use the existing invoice pricing, discount, and tax-rounding rules. Lines expose both recorded unit prices and their rounded subtotal after any pricing multiplier. Discounts retain their configured flat amount or rate; the combined applied discount is in `amounts`. The discounted subtotal is floored at zero. Paid invoice applications use the latest payment status PAID; processing uses PENDING or PROCESSING. `open_balance_cents` is the signed remainder for OPEN invoices and zero for other statuses. Refunds do not automatically increase this balance, and this API does not invent invoice-level refund allocation. A payment with no recorded status has `status: null`; its invoice applications also have `payment_status: null`. These records remain readable and contribute neither paid nor processing invoice amounts nor received collections. ## Collections and refunds Received collections count only payments currently PAID. Refunded collections count only refunds currently SUCCEEDED. A later refund reduces the period of the refund, not the earlier payment period. Occurrence date supports backdating and is not bank settlement. Refund grouping by collector uses the original payment's collector. Collections do not support business-unit, job-type, or technician-participation grouping, because refunds have no recorded split across invoices. Count each payment once, even if it is allocated across several invoices. Read `/payments` for the complete allocation set and `/refunds` for refunds on their own dates. Invoice payment applications explain invoice balances; they are not additional payments. ## Current receivables AR groups OPEN invoices by account, retaining positive, zero, and negative balances. Buckets are current, 1–30, 31–60, 61–90, and 91+ days past due. Due today and future due dates fall in current. A legacy OPEN record without a due date is represented as current with null `days_past_due`; new OPEN invoices require a due date, and the worked example uses September 30. For dated invoices, days past due is the signed company-local calendar-day difference. Non-open invoices have null aging. The summary's `report.aging_date` is the current local date; there is no historical `as_of` parameter. Its detail is `/invoices?status=OPEN` with identical account/business filters. Processing applications are separately visible. For refreshing open invoices without losing ones that became paid, follow [Build a reporting store](/reporting-store). # Recorded job profitability Source: https://breezy-fsm.mintlify.app/job-profitability Use saved job costs and the existing costing revenue and report-date basis. Recorded job costs and profitability are available at `/job-financials`, with a matching detail read using the job ID. Each resource includes the complete saved cost entries, qualifying invoice facts, current costing state, work dimensions, and distinct assigned company members. Pages order by job ID ascending. All jobs with an available owned account remain readable, including untracked, unverified, or excluded jobs. Missing or disabled company costing and untracked jobs have `totals:null`; saved costs and invoice facts remain available. Enabled tracked jobs retain their calculations regardless of verification or type inclusion. ## Query details or a summary ```sh theme={null} curl "https://api.getbreezyapp.com/v1/job-financials?report_from=2026-09-01&report_before=2026-10-01&limit=100" \ -H "Authorization: Bearer $BREEZY_API_KEY" curl "https://api.getbreezyapp.com/v1/reports/job-profitability?start_date=2026-09-01&end_date=2026-10-01&bucket=week&group_by=business_unit" \ -H "Authorization: Bearer $BREEZY_API_KEY" curl "https://api.getbreezyapp.com/v1/reports/technician-participation-profitability?start_date=2026-09-01&end_date=2026-10-01&bucket=month" \ -H "Authorization: Bearer $BREEZY_API_KEY" ``` ## Revenue and report date Costing revenue follows the existing job-costing dashboard: recorded invoice subtotals before discounts and taxes, for linked OPEN, PAID and UNCOLLECTABLE invoices. This differs from public invoice activity, collections, and recognized revenue. The complete `invoices` facts explain that revenue basis. The whole job uses the company-local date of its earliest qualifying non-null invoice issue time, falling back to work completion and then job creation; `report_date_basis` names the chosen source. All its current revenue and costs appear on this date, even if a later invoice or cost was recorded in another month. ## Costs, gross profit, and margin Each saved labor cost is its recorded minutes / 60 × hourly cost; other categories use recorded quantity × unit cost. Each entry rounds to integer cents before summing, with half-cent ties away from zero. Unknown category strings are preserved and contribute `other_cost_cents`. Gross profit is revenue minus total cost; `gross_margin` is a fraction rounded to four decimal places, null at zero revenue, with signed amounts retained. A 0.7692 margin means 76.92%. In the examples, invoices 1001 and 1002 supply $1,300 recorded subtotal on August 20; $300 saved costs produce $1,000 gross profit. This is distinct from the invoices' $1,290 combined after-discount-and-tax total and their separate invoice-activity months. Costs are saved business records. Reading this API does not populate missing costs from timesheets, synchronize invoice lines, or recalculate them using current wages or pricebook costs. A cost's `source` describes its recorded origin; it does not identify a worker or allocate revenue. Verification is the current recorded state, without an inferred verifier or approval timestamp. Current costs may differ from a later app visit that synchronizes them. Profitability amounts must fit the documented signed integer range of −9,007,199,254,740,991 through 9,007,199,254,740,991 cents. A saved quantity or a sum of otherwise valid costs/jobs can exceed that range. Such a request returns the standard 500 `INTERNAL_ERROR` with no partial result; the API does not round away financial precision, clamp amounts or omit contributing records. Correct the source data, narrow the report scope where possible, or share `request_id` with support. Repeating an unchanged out-of-range query cannot recover the result. ## Report eligibility and grouping Both profitability reports always require enabled company costing and TRACKED jobs. Defaults also require VERIFIED and a job type included in costing. Set `verified_only=false` or `include_excluded_job_types=true` to relax those respective rules; the latter includes jobs whose owned type is unavailable. A disabled report has empty data and `report.costing_enabled:false`. It does not claim the company earned zero profit. Dates and time buckets follow the [shared half-open local-date conventions](/conventions); empty buckets are omitted. Job profitability allows one `group_by` of business\_unit, job\_type or job\_class and keeps eligible unknown business groups. Both reports support account, business unit, job type/class and assigned-member filters. Overall margin must be calculated from summed revenue and profit, not averaged row margins. For overlapping member totals, read [Technician performance](/technician-performance). ## Refresh the detail records To build a local profitability store, page `/job-financials`, upsert by job ID, and replace each refreshed job's embedded invoices, costs and participants. Join `/jobs`, `/accounts`, `/team-members` and business catalogs for further segmentation. Collection filters include IDs, location, work dimensions, member, tracking/verification state, job-creation timestamp bounds and inclusive/exclusive local `report_from`/`report_before`. There is no financial `updated_since`: dependent invoices, costs, assignments, type inclusion and company configuration can change without a reliable shared timestamp. Refresh known job IDs and recent report-date windows, then periodically reconcile broader scopes. Corrections can move a job between dates or remove saved costs/assignments. A missing result in a filtered window does not prove deletion. Summary cursors page current results rather than freezing a snapshot. # Leads and estimates Source: https://breezy-fsm.mintlify.app/leads-and-estimates Measure current pipeline, accepted proposal values, and recorded marketing sources. ## Query a sales cohort ```http theme={null} GET /v1/job-leads?created_from=2026-09-01T07:00:00Z&created_before=2026-10-01T07:00:00Z GET /v1/estimates?status=ACCEPTED&accepted_from=2026-09-01&accepted_before=2026-10-01 GET /v1/estimates?job_id=11111111-1111-4111-8111-000000000501 ``` ## Leads and marketing sources Job leads preserve the lowercase states `open`, `converted`, and `archived`, including all by default. Their contact/address objects contain nullable captured submission values, not live CRM records or fabricated contact/address IDs. `request_type`, `submitted_account_type`, and legacy `submitted_service_type` retain recorded text; `submitted_job_type` is a separate configured reference. `source_text` is free-form intake text and does not identify a configured `/lead-sources` record. The example's `Booking Website` text and its job's `Referral` source are distinct recorded facts. Do not map one to the other automatically. Lead filters include repeated `status`, `job_id`, `existing_location_id`, `submitted_job_type_id`, `request_type`, and exact case-sensitive `source_text`. A lead's `job_id` is a recorded conversion link, not proof of a sale or payment. Two leads can reference one job: count lead IDs for requests and distinct linked job IDs for converted jobs. There is no stored conversion timestamp or conversion actor; `updated_at` also changes for summary and other edits. Do not use it or job creation time as a conversion event date. Provider recordings, transcripts, signatures, arbitrary platform links, and availability blobs are not part of these reporting records. ## Estimate options and accepted value Estimates contain complete ordered `options`, each with its own `line_items`, `discounts`, selection/recommendation flags, and recorded `total_cents`. Options are alternatives: never add their values together as one estimate's value. The example's selected repair option is $990, while its recommended replacement alternative is $8,800. The estimate's `accepted_total_cents` is \$990. A recommendation alone does not establish selection or acceptance. For a current `ACCEPTED` estimate with zero or multiple selected options, accepted value is null. Other statuses also return null, even if an acceptance timestamp or selected flag remains populated. Option totals are the current saved proposal values. They are not recalculated from the current catalog or invoice calculations. Constituent unit prices, fractional quantities, configured flat/rate discounts, the estimate tax name/rate, option tax-rounding context, and presentation/conversion pricing multiplier remain available. Saved option totals can differ from invoice calculations, including their dynamic-pricing treatment; do not manufacture a reconciled tax/subtotal breakdown or multiply an option total again to establish accepted value. Tax rounding follows company configuration at the option's creation, with the application's `ceil` fallback. Invoice amounts retain their separately documented calculated basis. ## Acceptance and other dates `accepted_at` is the recorded acceptance timestamp and can remain after reopening. Accepted proposals can also be edited, so `accepted_total_cents` is the current selected-option value, not a frozen sale event at that timestamp. `created_by` identifies the original proposal creator. `accepted_on_behalf_by` preserves the recorded staff proxy and may remain from an earlier acceptance; it is not a seller or signing history. `last_sent_at` records the latest send attempt, not confirmed delivery. Loss category/note are current recorded fields; later status changes can clear them. The API provides no inferred review, first-send, expiration, loss, or status-transition dates. Messages and option/discount descriptions use plain text. Estimate filters include `job_id`, `account_id`, `business_unit_id`, `job_type_id`, `job_class`, `created_by_id`, and repeated `status`. `accepted_from`/`accepted_before` are inclusive/exclusive company-local dates on the recorded acceptance timestamp, independent of current status. Add `status=ACCEPTED` for currently accepted proposals. Creation-date cohorts and acceptance-date activity answer different questions. Both estimates and job leads support creation instant bounds and inclusive parent-only `updated_since`; option, line, discount, and invoice-link edits may not advance the estimate parent time. ## Join conversions An estimate's `job_id`, account, business unit, type, and class describe its original job. `invoice_ids` includes every recorded tenant-owned conversion, which may belong to another linked job/account. Do not assume there is exactly one invoice or that its job equals the original estimate job. Conversion copies line items, so estimate and invoice line IDs differ. Replace the complete embedded option/line/discount sets when refreshing a proposal, including children that have disappeared. ## Accumulate and refresh For sales reporting, accumulate leads and estimates by ID, join their job IDs to `/jobs`, and use estimate `invoice_ids` to find the corresponding invoices. Calculate creation cohorts from `created_at`, current conversion from lead status/link, and current accepted value from estimates. Retain null accepted values as unavailable rather than zero. On refresh, reread known open/outstanding IDs without the old status filter so accepted, archived, or closed records are observed, and periodically reconcile broader scopes for corrected children and hard deletions. These are customer-controlled refresh strategies, not a guaranteed synchronization feed or historical pipeline snapshot. # Pagination and filters Source: https://breezy-fsm.mintlify.app/pagination Accumulate complete records with opaque cursors and strict query parameters. ## Read every page Collections default to **50 parent records per page**, with a maximum of **100**. `data` contains the records, `pagination.next_cursor` contains a continuation token or null, and `meta` supplies request ID, generation time, and company timezone. Follow the cursor until null. Keep the same company, endpoint, and filters; the page size may change between requests. Most timestamped collections order by `created_at`, then `id`, ascending. Equipment, form responses, job financials and revenue attributions order by UUID `id` ascending; job classes order by code `id` ascending. These orders are fixed. Cursors are opaque and cannot be transferred to another company or endpoint. Report rows follow the same page-size rules. ```http theme={null} GET /v1/invoices?limit=2 Authorization: Bearer YOUR_API_KEY GET /v1/invoices?limit=1&cursor=example-opaque-cursor Authorization: Bearer YOUR_API_KEY ``` The fictional first page contains invoices 1001 and 1002, with complete children. The second contains 1003 and a null cursor. `example-opaque-cursor` illustrates the format; only a real API response would supply a usable token. Both list and detail reads return the same invoice shape. Page limits apply to parents, never silently to their children. Large documents may therefore produce larger responses even at `limit=1`. ## Encode filters Omit a filter to leave it unrestricted, and omit `cursor` to start the first page. A null query-schema default represents an omitted value; do not send the literal string `null` or an empty value. Combine documented filters with AND. Repeated `ids` or `status` values mean OR within that field; use `ids=ID_A&ids=ID_B`, not comma-separated values. Up to 100 IDs may be supplied. Foreign or missing IDs contribute no list results. Repeated scalar parameters, empty values, invalid UUIDs, unknown query parameters, and unsupported filters return 400. Valid filters matching no records return an empty page with a null cursor. `created_from` and `created_before` are inclusive/exclusive instants. Invoices and payments support `updated_since` as an inclusive parent-row edit instant; payments with null `updated_at` do not match it. Refunds do not support this filter. `issued_from`/`issued_before` and `occurred_from`/`occurred_before` are inclusive/exclusive company-local dates. A supplied upper bound must be later than its lower bound. Null dates do not match date filters. Invoice lists include every status by default; `status=OPEN` provides AR detail. The invoice-activity summary defaults to OPEN and PAID instead. Use a query-string encoder rather than assembling cursor values or timestamp offsets by hand: ```sh theme={null} curl --fail-with-body --silent --show-error --get "https://api.getbreezyapp.com/v1/invoices" \ --header "Authorization: Bearer $BREEZY_API_KEY" \ --data-urlencode "ids=$BREEZY_INVOICE_ID_A" \ --data-urlencode "ids=$BREEZY_INVOICE_ID_B" \ --data-urlencode "limit=10" ``` ## Refresh after the first pass Keep successful pages when a request fails and retry the same cursor. Treat a multi-page report as incomplete until its last page succeeds. See [Build a reporting store](/reporting-store) for refresh and reconciliation strategies. Reads use latest corrected records. A cursor and `generated_at` do not freeze data across requests. The API offers no guaranteed incremental synchronization or deletion feed, and an `updated_since` query does not cover all dependent changes. Clients may observe corrections between pages; retry or refresh the relevant query when reconciling current results. Responses should be treated as private company data and use `Cache-Control: private, no-store`. # Make your first request Source: https://breezy-fsm.mintlify.app/quickstart Read your company and page through jobs in a few minutes. Use this read-only API to build operational and financial reports and maintain your own reporting store. Examples use fictional records and placeholder credentials. The production base URL is `https://api.getbreezyapp.com/v1`. The API uses ordinary REST GET requests and JSON responses. ## 1. Supply your company API key Set `BREEZY_API_KEY` in your environment to the key you were issued. Ask your Breezy contact for an API key if you do not have one. Read [Authentication](/authentication) before sharing a key with a reporting tool. ## 2. Identify your company and read jobs ```sh theme={null} BREEZY_API_ORIGIN=https://api.getbreezyapp.com : "${BREEZY_API_KEY:?Set BREEZY_API_KEY to your issued API key}" curl --fail-with-body --silent --show-error "$BREEZY_API_ORIGIN/v1/company" \ --header "Authorization: Bearer $BREEZY_API_KEY" \ --header 'Accept: application/json' curl --fail-with-body --silent --show-error "$BREEZY_API_ORIGIN/v1/jobs?limit=2" \ --header "Authorization: Bearer $BREEZY_API_KEY" \ --header 'Accept: application/json' ``` A successful request returns HTTP 200. `/company` returns the company in `data`, including its `timezone`; a jobs collection returns `data` and `pagination`. ## 3. Continue to the next page Read the company ID and timezone from `/company`. Store each job from the page's `data` array by its `id`. To continue, use the returned `pagination.next_cursor` with the same endpoint and filters; stop when it is null. For example, after assigning the returned token to `BREEZY_CURSOR`: ```sh theme={null} curl --fail-with-body --silent --show-error --get "$BREEZY_API_ORIGIN/v1/jobs" \ --header "Authorization: Bearer $BREEZY_API_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'limit=2' --data-urlencode "cursor=$BREEZY_CURSOR" ``` Keep already stored pages when a request fails. For a 429, wait the response's `Retry-After` seconds and retry the same request. A first collection pass accumulates records; later refreshes can target [supported edit/date filters and known IDs](/reporting-store). Cursors do not provide a snapshot or a complete change feed. Choose joins and a refresh strategy for your own database. Find the right records and summaries for each report. Download the [OpenAPI specification](/openapi.json) for the complete reference, or give an agent the [documentation index](https://developers.getbreezyapp.com/llms.txt). # Build a reporting store Source: https://breezy-fsm.mintlify.app/reporting-store Page once, upsert by identity, and choose bounded refreshes for current corrected data. ## 1. Accumulate the records you need For a customer reporting store, first read `/company` and accumulate the reference catalogs and `/team-members`. Page `/accounts`, `/contacts`, `/locations`, `/jobs`, `/job-appointments`, and `/job-assignments`, upserting by ID. Join an invoice's `job_id` to jobs, an appointment's `job_id` to jobs, and an assignment's `appointment_id` to appointments and `team_member.id` to members. Count each visit once before joining multiple assignments. For example, two assignments on one visit are two member assignments, one visit, and one job. Segment invoice values by the invoice's recorded dimensions; this API does not allocate revenue across participating members. Persist the exact query and its next cursor after each successfully committed page. If you flatten a document into several tables, commit the parent and replacement child sets together before advancing the cursor. Start with a small page size when measuring response size. ## 2. Preserve each resource’s grain | Local record | Identity and replacement rule | | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Account, job, invoice, payment, estimate, time entry, equipment, or form response | Upsert by `id`; replace complete embedded children for each refreshed parent. | | Job financials or revenue attributions | Upsert by the job `id`; replace costs, invoices, participants, or the complete credits array. | | Payment allocation | Payment ID + invoice ID. Count the parent payment once for collections. | | Timesheet | Team-member ID + resolved start/end dates. Replace the complete configured period. | | Summary | Page the entire query before replacing that scoped result. It describes current corrected records. | ## 3. Refresh a bounded scope For subsequent refreshes, read new records by creation range, parent edits where supported, and active/recent job IDs with their visits and assignments. Re-read selected known older IDs to capture corrected child state; an open-only or incomplete-only query misses records that moved out of that state. Small reference catalogs and member profiles can be reread in full. These approaches let customers control refresh scope without repeatedly downloading every company record, but they do not guarantee complete change capture. Invoice `updated_at` tracks its underlying parent row. Payment `updated_at` is the recorded parent edit time and is null when unavailable. Related payment statuses, allocations, children, or business references may change without advancing these timestamps. Refunds expose `created_at` and `occurred_at`, with no `updated_at` field or `updated_since` filter. Choose windows based on how far back your business normally corrects data. Parent `updated_since` is useful where supported, but it does not capture every child or relationship edit. Retain the IDs of records that were active or outstanding so you can reread them after they leave that state. ## 4. Reconcile state changes For a local reporting store, page the collections, upsert parents by ID, and replace each refreshed parent's embedded child set when flattening it. Later, read recent activity and parent edits with supported filters. To refresh open invoices, also re-read previously open IDs without a status restriction; an invoice that became PAID would disappear from an open-only query. Alternatively, replace a scoped local AR result after paging the entire current open-invoice query. That replacement affects the current result, not the customer's broader invoice history. Periodic reads of selected older periods can capture corrections. A missing row in a filtered response does not prove deletion. A customer-controlled broader reread is needed when you require confidence about older corrections or hard deletions. Never delete a locally stored record just because it is absent from a filtered page. The API has no snapshot, tombstone stream, or guaranteed change feed. ## Pick the relevant refresh rules Refresh limits differ by resource. Read [Work and customers](/work-and-customers), [Leads and estimates](/leads-and-estimates), [Time reporting](/time-reporting), [Equipment and forms](/equipment-and-forms), [Job profitability](/job-profitability), and [Saved revenue attribution](/revenue-attribution) for the records you store. # Saved revenue attribution Source: https://breezy-fsm.mintlify.app/revenue-attribution Read complete sold and earned credit sets and summarize them by work-completion date. Saved sold and earned credits are available at `/revenue-attributions` and `/revenue-attributions/{id}`, where `id` is a job ID. Every owned job with an available owned account has a representation, including jobs with `credits:[]`. Page by job ID ascending and replace each refreshed job's complete array. A credit records its type, signed `revenue_cents`, credited member, optional current invoice and matching invoice line IDs. Credits have no separate public IDs or save timestamps. ## Query credit details or member totals ```sh theme={null} curl "https://api.getbreezyapp.com/v1/revenue-attributions?report_from=2026-09-01&report_before=2026-10-01&limit=100" \ -H "Authorization: Bearer $BREEZY_API_KEY" curl "https://api.getbreezyapp.com/v1/reports/revenue-attribution?start_date=2026-09-01&end_date=2026-10-01&bucket=month" \ -H "Authorization: Bearer $BREEZY_API_KEY" ``` ## Independent credit measures Credits are the amounts explicitly saved by the company. Each selected person can receive the whole item amount independently for SOLD and EARNED. Keep those measures separate, and do not sum member credit rows as company revenue. Zero and negative credits remain meaningful recorded entries. Reading does not infer credit from participation, divide it among people, recalculate invoice prices, or require current payment status, job-cost tracking or verification. ## Report dates and totals `report_date` is the company-local date of `work_completed_at`, with no fallback. The summary uses this date, matching the existing backend technician-performance export; the current team dashboard uses revenue recognition (closure, then work completion), so date selection can differ. Jobs without work completion remain readable with a null report date and do not contribute to any dated summary. The report uses the [shared half-open date ranges, clipped day/week/month/quarter/year buckets, and omitted empty buckets](/conventions). The summary always groups by credited team member. It returns separate `sold_revenue_cents`, `earned_revenue_cents`, their respective credit counts, and the distinct count of jobs with contributing credits. A zero sum with a positive credit count differs from no recorded credit. Inactive and non-technician members remain named. A null member group retains saved credits for unavailable people and can combine several people. It does not assert an anonymous person or invent a replacement identity. ## Current references and joins Current references provide context for saved credits. Missing or foreign people and invoices become null while the owned credit amount remains included. Invoice context requires a currently owned invoice and account with that job link, regardless of invoice status. `invoice_line_item_ids` lists current owned invoice lines matching the recorded cart key or owned original pricebook key. Several lines can share one original catalog item and match one saved credit; count that credit once. An empty array means no currently resolvable matching line. Do not recalculate a historical credit from the current matching lines, or use array positions as durable credit IDs. Identical-looking entries with unavailable references remain separate saved credits. Join the parent ID to `/jobs` and `/job-financials`, `team_member.id` to `/team-members`, and `invoice.id` to `/invoices`; match line IDs within that invoice's `line_items`. Collection filters include job IDs, location, account, business unit, job type/class, job-creation bounds and completion-date `report_from`/`report_before`. `team_member_id` and `credit_type` must match the same credit to select a job, but its returned array remains complete. In the report those filters select contributing credits, so filtering SOLD leaves earned count and cents at zero. There is no grouping override, inferred attribution mode or combined sold-plus-earned total. ## Refresh complete credit sets Attribution has no reliable `updated_since`: saves replace entire job credit sets and related records can change independently. Refresh known job IDs and recent completion-date windows, then periodically reconcile broader scopes. Replace complete arrays, including newly empty arrays. Work-date corrections can move a job between windows or make it undated; absence from a filtered window is not a deletion signal. Report cursors page current results rather than a snapshot. As with profitability, amounts outside the safe integer cents range return the standard 500 without rounding, clamping or partial results. # Technician performance Source: https://breezy-fsm.mintlify.app/technician-performance Choose participation or saved sold and earned credit without inventing an attribution model. Use the measure that matches the question. Participation works with saved job financials and retained assignments. Sold and earned attribution uses credits the company explicitly saved. | Question | Endpoint | Meaning | | -------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------ | | What profitable work did each member participate in? | `/reports/technician-participation-profitability` | Full job financials once per distinct assigned member. | | What sold or earned credit was recorded for each member? | `/reports/revenue-attribution` | Separate saved SOLD and EARNED amounts. | | What is company gross profit? | `/reports/job-profitability` | Eligible job financials once per job. | ## Participation Technician participation always groups by assigned team member. Each distinct current company member receives a job's entire financial result once, even with several appointments or assignments. Inactive members, non-technician roles, and canceled visits remain included when their assignment is retained; assignment is not evidence of attendance. A job with two members contributes its full amounts to both members, so these rows overlap and must not be added into company totals. Jobs without members stay in job profitability but have no participation row. `team_member_id` selects distinct jobs for job financials and job profitability; in participation it selects only that member's rows. This follows the existing participation model and does not infer sold/earned attribution or divide profit among workers. For example, a job with $1,300 costing revenue and $1,000 gross profit assigned to two members contributes $1,000 profit to each member’s participation row. Company job profit remains $1,000. Adding member rows would double-count it. Participation uses the [job-costing report date and eligibility rules](/job-profitability). Saved attribution instead uses the company-local work-completion date and does not require costing to be enabled. ## Saved sold and earned credit SOLD and EARNED are independent measures; never combine them into one revenue total or sum people’s credits into company revenue. Read [Saved revenue attribution](/revenue-attribution) for complete credit arrays, line references, dates, and refresh behavior. ## Activity and hours Use [Work and customers](/work-and-customers) for visits, assignments, and recorded creators. Use [Time reporting](/time-reporting) for effective intervals and payable minutes. Job creation does not identify a seller or dispatcher, and an assignment does not prove attendance. The API does not infer missing CSRs, dispatchers, or revenue credit. # Time entries and timesheets Source: https://breezy-fsm.mintlify.app/time-reporting Compare effective elapsed work intervals with configured-period payable totals. Timekeeping is available through `/time-entries` and `/timesheets`, with matching detail reads. Time entries contain effective corrected start/end instants, correction flags, raw elapsed minutes, recorded activity/payable state, and work/member links. Custom activity names retain their recorded text. Missing or ambiguous activity produces null activity and payable fields; it does not create duplicate intervals or an inferred activity. ## Read entries and a configured period ```sh theme={null} curl "https://api.getbreezyapp.com/v1/time-entries?starts_from=2026-09-01T07:00:00Z&starts_before=2026-10-01T07:00:00Z&include_deleted=true&limit=100" \ -H "Authorization: Bearer $BREEZY_API_KEY" curl "https://api.getbreezyapp.com/v1/timesheets?period_date=2026-09-08&limit=100" \ -H "Authorization: Bearer $BREEZY_API_KEY" ``` ## Time-entry filters and corrections `starts_from` is inclusive and `starts_before` exclusive, matching effective start instants rather than interval overlap. Entry collections order by creation instant and ID, including timestamp ties. Filters include member, job, appointment, assignment, exact activity name, payable state, open state, and creation/effective-start bounds. Lists and details require `include_deleted=true` to return retained soft-deleted entries. The entry's modification timestamp is unavailable, so `updated_since` is unsupported. Refresh known IDs and bounded effective-start windows to observe corrections and deletions; a correction can move an entry into another window. Current relationships and hard deletions require customer reconciliation, as with the other collections. ## Timesheet identity and period Timesheets require one company-local `period_date` and resolve the current configured period containing it. Results identify the member plus inclusive `period.start_date` and exclusive `period.end_date_exclusive`; these form the customer-side key. Use that exclusive end as `period_date` for the next period. Page members by cursor, or use `team_member_id` to select one; `/timesheets/{team_member_id}?period_date=...` returns the same member representation. All current company members are included, regardless of role or active state, including zero-entry members. Changing company period settings can change historical results and invalidates cursors whose resolved boundaries change. Missing or unusable settings return 400; disabled tracking still permits reads of retained data. There is no historical configuration snapshot or fabricated timesheet ID. ## Payable minutes Timesheet inputs are nondeleted entries starting within the resolved local period. The response includes entry, open-entry, and unknown-activity counts, every local day (including zeros), and total payable minutes. Only completed entries with a known payable activity contribute minutes. Totals follow the existing server timesheet calculation: whole wall-clock minutes, a running daily clamp of 0–1,439, and overnight time only through the end of its starting day. Negative/overlapping records follow those same recorded-data rules. Last-day overnight entries follow the same rule as other overnights. `duration_minutes` on the entry remains fractional elapsed time across its whole span. For example, a corrected on-site entry from 12:30 to 13:30:30 has 60.5 elapsed minutes and contributes 60 payable timesheet minutes. A 22:00–02:00 overnight contributes 119 minutes to its starting day. In Los Angeles, the spring daylight-saving interval 01:30–03:30 and fall interval 00:30–02:30 each contribute 120 wall-clock timesheet minutes, while raw elapsed durations are 60 and 180 minutes. Existing browser summaries can differ with the browser timezone and their end-containment selection. These resources describe current corrected timekeeping; they do not calculate payroll, overtime, wages, approvals, or job-cost labor amounts. ## Supported period configuration Configured periods are bounded to 366 calendar days. Supported cadences are daily (interval 1–366), weekly (1–52), monthly (1–12), and yearly (1), using the settings page's weekday and month-day/ordinal modes. Anchor time-of-day is normalized to its company-local calendar date. Recurrence phase stays anchored when requesting historical periods. Date-based month/year boundaries clamp to the target month's end (January 31 → February 28 → March 31; February 29 returns in leap years); an absent fifth weekday is skipped. Unsupported or nonprogressing recurrence settings return the same configuration-unavailable 400, without a fabricated fallback period. # Use the API with an agent Source: https://breezy-fsm.mintlify.app/using-agents Give an agent the documentation and a securely configured company key. An agent can discover the API through the [documentation index](https://developers.getbreezyapp.com/llms.txt), [complete Markdown documentation](https://developers.getbreezyapp.com/llms-full.txt), and [OpenAPI specification](/openapi.json). Individual documentation pages are also available with `.md` appended to their URL. OpenAPI describes exact operations and schemas; the guides explain which business measures to use. ## Configure access Provide the key through the agent’s secret or environment mechanism, for example `BREEZY_API_KEY`. Give it permission to make read-only HTTPS requests to `https://api.getbreezyapp.com/v1`. Use the [authentication guide](/authentication) for company scope. Avoid pasting credentials into a prompt or documentation search. ## Example task ```text theme={null} Use the Breezy FSM documentation index and OpenAPI specification. The company API key is already available as BREEZY_API_KEY. Build a local report of September 2026 issued invoice activity by business unit. Read /company first to establish the timezone. Use the documented invoice-activity summary and follow every cursor. Explain the statuses, date bounds, amount basis, and missing groups. Keep the key out of logs and output. Report any unfinished pages. ``` ## Check the result Before relying on the output, check that the agent used the correct company timezone, fetched every page, distinguished cents from dollars, and reported its date and amount basis. For technician results, check [participation overlap and separate sold/earned measures](/technician-performance). For local stores, check [refresh limitations](/reporting-store). This is a read-only reporting API. Its documentation does not define write endpoints, webhooks, historical snapshots, or a complete change feed. # Work and customers Source: https://breezy-fsm.mintlify.app/work-and-customers Join customers, service locations, jobs, visits, and assigned team members. ## Choose the row you are counting Count appointments as visits, assignments as member assignments, and distinct `job_id` values as jobs. One appointment can have several technicians; one technician can have several appointments for the same job. Assignment presence and scheduled duration do not prove attendance or hours worked. Missing execution status is null. Missing confirmation/cancellation state means false, matching the application's current visit state. Member business-unit assignments retain recorded calendar ranges with inclusive `start_date` and inclusive `end_date`; a null end has no recorded end. Do not replace a job's recorded business unit with the member's current business unit. ## Customer relationships Account/contact and account/location associations can be many-to-many. `is_primary` and relationship `archived` belong to a particular account association; a location has no global archive flag. Contact association IDs identify individual links. Replace complete embedded relationship sets when refreshing a parent, including links that changed primary/archive state. Lifecycle `statuses` likewise remains complete and follows configured order, with unsequenced statuses ordered by creation time and ID. ## Job status and attribution Jobs expose the current configured status name alongside its existing `stage` and `special_status` meaning. Work completion and lifecycle closure are separate: a canceled job can retain a completion timestamp, and reopening can clear closure. These values are not a status-transition history. Nullable outcomes remain unknown, rather than false. A job's `lead_sources` are its explicitly recorded source links; account acquisition sources are separate and are never substituted for missing job attribution. `created_by` records creation activity; it does not identify the seller or dispatcher. ## Member and archive state Operational records retain inactive and archived state by default; archive filters are optional. Boolean filters accept only `true` or `false`. A team member's roles describe business responsibilities, never API permissions. Membership determines visibility: deactivated members remain readable, but users who no longer belong to this company are unavailable. Membership `created_at` means when the member was added. `updated_at` is explicitly null because no member-level edit timestamp is available; `updated_since` is unsupported for team members. ## Date filters and edits Assignments also return `updated_at: null` and reject `updated_since`: reassignment and rescheduling do not maintain that timestamp. Their separate `status_updated_at` describes only execution-status edits. All remaining timestamped operational collections support `created_from`, `created_before`, and inclusive parent `updated_since`. Locations may have a null update time, which does not match that filter. Child association, role, confirmation, cancellation, and execution-status changes can alter responses without advancing parent timestamps. Job classes have no timestamps. An account's `customer_since` is its recorded customer-since instant, which may predate its technical `created_at` after an import; it is not inferred from the first job or payment. Jobs additionally accept company-local date bounds `completed_from`/`completed_before` for `work_completed_at`, and `closed_from`/`closed_before` for `lifecycle_closed_at`. The start is inclusive and the end exclusive. A local day can span 23 or 25 hours across daylight-saving changes. Appointment and assignment `starts_from`/`starts_before` instead accept precise instants and filter the recorded start, not any overlap with a range. Use the company's timezone when grouping returned timestamps into local reporting periods. ## Example requests ```http theme={null} GET /v1/jobs?completed_from=2026-09-01&completed_before=2026-10-01&job_class=SERVICE GET /v1/job-appointments?job_id=11111111-1111-4111-8111-000000000501 GET /v1/job-assignments?team_member_id=11111111-1111-4111-8111-000000000401 GET /v1/job-classes/SERVICE ``` Use [Build a reporting store](/reporting-store) for the collection order and join keys. Use [Technician performance](/technician-performance) when the question involves financial credit or profitability.