> ## 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.

# Leads and estimates

> Measure current pipeline, accepted proposal values, and recorded marketing sources.

## Query a sales cohort

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
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.
