Skip to content

Offer letters

When you write a real-estate offer, three documents typically ride alongside the purchase agreement: a one-page summary the seller’s agent uses to brief the seller, a buyer cover letter introducing your client, and (later, often several rounds later) a counter-offer comparison so your buyer can see exactly what changed. My Agent Platform’s Offer Letter Generator drafts all three on demand. The summary and the counter comparison are pure-template — no LLM cost, no waiting. The cover letter uses your BYOK key, runs through the Fair Housing scanner before it lands on your screen, and is hard-blocked in states where buyer love letters are illegal.

The tool lives behind your agent. Ask in chat — “draft the offer summary for the Maple Drive listing, $525K, 20% conventional” — and the platform persists a draft offer, renders the summary, and returns the table on the spot. Three doc types come out of the same tool:

  1. Offer Summary — a clean two-column table covering buyer(s), price, financing, earnest money, contingencies, escalation, and concessions. No LLM. Fast. Always available regardless of state.
  2. Buyer Cover Letter — 200-350 words in your voice, drawing only on the buyer notes you provide. Fair Housing scanned before it returns. State-gated: in jurisdictions where these are illegal (Oregon today), the tool returns a polite refusal instead of generating one.
  3. Counter-Offer Comparison — a side-by-side diff of the original and the seller’s counter, with a plain-language summary and an estimated out-of-pocket-impact number. Append a new round each time the seller revises.

The tool is also stateful. Each (agent, property) pair has one active draft. Re-running the create command updates the existing draft instead of duplicating it. When you finalize or archive an offer, the slot opens up and you can start a fresh draft on the same property.

Five typical exchanges, with what the agent does behind the scenes.

Draft the summary

“Draft an offer summary for the Maple Drive listing — $525K, 20% conventional, 30-day close, 10-day inspection.”

The agent looks up the listing in your saved inventory, captures the offer fields, persists a draft row in the offers store, and returns the rendered summary table. You can ask for adjustments — “make the inspection 7 days” — and the row updates in place.

Write the cover letter

“Write the buyer cover letter. Buyer notes: ‘they love the original bookshelves, they’ve been renting nearby in Hawthorne for 4 years and want to put down roots.’”

The agent calls the cover-letter writer with those notes, the cover letter prompt, and your saved voice profile. The output goes through the Fair Housing scanner. If clean, you get a 200-350 word letter back with a sign-off “Sincerely, [buyer names]” and a short legal disclaimer line. If the scanner hard-blocks it, the letter is rejected and you’re told why; the buyer notes can almost always be tightened to fix it.

Compare the seller’s counter

“The seller countered at $535,000 with a 7-day inspection — what’s the impact?”

The agent runs the counter against the original draft, returns a markdown comparison table with the changed rows highlighted, and tells you the estimated additional out-of-pocket cost. The round is appended to counter_history on the offer row so you have an audit trail of every revision.

Oregon property (state-blocked)

“Draft a cover letter for the Portland offer.”

The agent recognizes the property is in Oregon and returns: “Oregon law (ORS 659A.421, effective 2022) prohibits buyer-to-seller love letters in residential real estate transactions to prevent Fair Housing discrimination. Cover letter generation has been skipped. You may submit the offer summary and purchase agreement without one.” No BYOK token spent. No retry. No work-around.

Multi-round counter

“The seller is back at $530K and 8-day inspection now — round 3.”

Each call is stateless from the comparator’s perspective; the agent always diffs the seller’s latest against your current draft terms, then appends to counter_history so you can scroll back through every round.

The summary is a deterministic template. The fields you provide go straight into a two-column table. Required fields: property_address, offer_price, financing_type (Conventional / FHA / VA / USDA / Cash). Optional fields enrich the table: buyer_names, down_payment_pct, earnest_money, closing_timeline, contingencies (inspection_days, appraisal, financing, sale_contingency_address, proof_of_funds), escalation (max_price, increment, proof_required), concessions, pre_approval_lender.

Two automatic adjustments worth knowing about:

  • Cash auto-removal — if financing_type='Cash', the financing-contingency row is omitted entirely. The financing cell reads “Cash”; if proof_of_funds=true, it reads “Cash — proof of funds attached”.
  • Escalation sanity check — if the escalation cap is at or below the offer price, the rendered summary appends a warning under “Additional Terms” so you don’t ship a contradictory escalation.

Example rendered table (markdown):

| Field | Value |
| --- | --- |
| Buyer(s) | Sarah Chen & Marcus Chen |
| Offer Price | $525,000 |
| Down Payment | 20% ($105,000) |
| Financing | Conventional — Pre-approved, Wells Fargo |
| Earnest Money | $10,000 |
| Closing Date | 30 days |
| Inspection | 10-day contingency |
| Appraisal | Contingent |
| Financing Contingency | Contingent |
| Sale Contingency | None |
| Escalation | Cap $540,000, increment $5,000, proof required |
| Concessions | $5,000 closing-cost credit |
| Additional Terms | None |

A short legal disclaimer follows the table on every render: “This summary is provided for review convenience and does not constitute a binding offer. Please refer to the attached purchase agreement for all terms and conditions.”

The cover letter is the only document in this tool that calls an LLM. It uses your BYOK LiteLLM key, runs through minimax/MiniMax-M2.7 at temperature 0.5, and is targeted at 200-350 words in five sections: (1) opening connection to the home, (2) what the buyers envision living there, (3) brief personal context drawn ONLY from the buyer notes you provide, (4) gratitude for the seller’s time and care, (5) closing line and “Sincerely, [buyer names]” sign-off plus a one-line legal disclaimer.

A few hard guardrails are baked into the prompt:

  • Anti-hallucination — if your buyer notes are sparse, the letter is short. The prompt explicitly forbids inventing professions, family situations, hobbies, pet ownership, or how long the buyers have lived in the area. Don’t try to prompt-engineer around it; provide better notes.
  • Fair Housing hard rule — the prompt forbids any reference to (or implication of) the buyer’s race, color, religion, national origin, sex, familial status, disability, age, or source of income. Same for the seller. Same for proximity to a place of worship, school district quality (a known proxy for demographics), or “family-friendly” / “kid-friendly” qualities of the neighborhood.
  • Voice profile — if your account has a saved voice profile (from listing-description training), the prompt includes a “Voice notes:” block so the cover letter sounds like you. No profile? The letter falls back to a neutral, warm tone.

After the LLM returns, the body is run through the same Fair Housing scanner used in Listing descriptions. Three outcomes:

  • Clean — letter returned, persisted with cover_letter_status='generated'.
  • Warn — banned-style phrase like “stunning” or “exclusive neighborhood” matched. Letter is still returned but the warns are surfaced so you can edit before sending.
  • Hard block — phrase like “perfect for families” or “no Section 8” matched. Letter is rejected with cover_letter_status='fair_housing_blocked'. There is no override. Adjust the buyer notes (most blocks come from the notes leaking into the letter body) and try again.

Unlike re_describe_listing (which has an allow_overrides=true escape hatch), cover letters cannot bypass the scanner. Reason: a flagged listing description is an MLS issue; a flagged cover letter is direct Fair Housing Act exposure for the listing agent who reads it.

When the seller sends back a counter, the comparator diffs the original offer (whatever’s currently on the row) against the counter and produces:

  • A markdown comparison table with one row per field — Offer Price, Down Payment %, Financing, Earnest Money, Closing Timeline, Inspection, Appraisal Contingency, Financing Contingency, Escalation Cap, Concessions.
  • A signed delta column — +$10,000, -3 days, Removed, Changed, No change.
  • An estimated out-of-pocket impact (price delta + concessions delta; earnest is excluded because it’s applied at closing either way).
  • A plain-language summary paragraph the agent can read aloud — “the seller is asking for $10,000 above your offer price, a shorter inspection window (7 days instead of 10), and reduced closing-cost assistance ($2,500 instead of $5,000). Your estimated additional out-of-pocket cost if you accept these terms is approximately $12,500.”

Each call to the comparator is stateless and idempotent. The agent appends each rendered round to counter_history on the offer row, so you can scroll back through round 1, round 2, round 3 with full diffs at every step.

The default mode is 'fast' — pure-template, no LLM cost. A 'rich' mode (LLM-generated paragraph summary) is planned for v2 but is currently disabled at the route layer.

A handful of US states have made buyer-to-seller love letters effectively illegal because of repeated Fair Housing violations. v1 lists one:

  • Oregon (banned) — ORS 659A.421, effective 2022. Cover-letter generation is hard-gated in code: the writer checks the property’s state BEFORE spending a BYOK token, and returns state_blocked with the citation if it matches.

Other states (Washington, California, Colorado) are monitored but not yet on the list. The data lives in app/services/state_compliance.py — adding a state is a one-line edit, surfaced on legislative cadence rather than agent self-serve cadence. v2 will add an admin UI; for now, file a request via the platform admin contact.

The state check accepts both 2-letter codes (“OR”) and full names (“Oregon”). The summary and counter comparison are not gated — only the cover letter, because that’s the doc fair-housing law targets.

Fair Housing primer (for cover letters specifically)

Section titled “Fair Housing primer (for cover letters specifically)”

A few examples of phrases you’ll see flagged in cover-letter drafts and what to do instead:

  • Religion — “we attend the church just down the street” → matches a religion phrase, hard-blocked. Don’t reference places of worship in the letter.
  • Familial status — “perfect for our growing family”, “ideal for our two children” → hard-blocked. The cleanest substitute is to focus on the home itself: “the layout is exactly what we’re looking for”.
  • Race / national origin — “we’d love to be part of this established neighborhood” → can warn (context-dependent). The comparison phrase “we love the bones of this house” is safer.
  • Source of income — “no Section 8” — hard-blocked, obviously.

The hard-block list is seeded from NAR fair-housing guidance and lives in the fair_housing_phrases table. The scanner does NOT auto-rewrite — it reports what it found. Editing the buyer notes is almost always the right fix; the LLM faithfully reflects whatever you give it.

Every cover letter ends with this line, automatically appended by the prompt:

This letter is provided to the seller for review and does not modify the terms of the attached offer.

Every offer summary includes:

This summary is provided for review convenience and does not constitute a binding offer. Please refer to the attached purchase agreement for all terms and conditions.

These are draft documents prepared for review purposes. They do not constitute legal advice and are not binding contracts. All offer documents should be reviewed by your broker or attorney before submission.

Offers, buyer notes, and generated documents never leave the platform until you copy them out. The cover-letter LLM call uses your BYOK key, so the text only touches the model you’ve provisioned through your own provider account. No third-party caching of generated documents. Buyer PII (names, notes) is stored encrypted-at-rest in our database and is only readable through your account.

A short list of deliberate omissions, all on the v2 roadmap:

  • PDF export — the tool returns markdown and plain text; PDF generation is deferred (typically the broker’s PDF stack does this anyway).
  • Per-state phrase additions via admin UI — adding to the state-compliance list requires a code change today.
  • Auto-detection of state from address — best-effort parse only; if the address doesn’t include a recognized state token, you’ll need to set property_state explicitly.
  • Programmatic API for third-party integrations — the tools are exposed via the agent’s chat surface and the dashboard. There is no third-party API key flow yet.
  • 'rich' counter summary — disabled at the route layer in v1; planned for v2 with a clear opt-in.

If any of these is blocking you, ping us on Discord — early-tier feedback shapes priorities.

What the agent will say if it can’t draft

Section titled “What the agent will say if it can’t draft”
  • No BYOK key: “Your LiteLLM key isn’t connected — set it up in Dashboard → Settings → BYOK so I can draft the cover letter.”
  • Oregon property: “Oregon law (ORS 659A.421) prohibits buyer cover letters. I drafted the offer summary instead.”
  • Fair Housing hard-block: “The cover letter draft hit a Fair Housing hard-block on the phrase ‘perfect for families’. I haven’t kept the draft. Adjust the buyer notes and ask again.”
  • Provider rate-limited: “The LLM provider rate-limited me; one moment, retrying.” (One automatic retry, then the call fails with transient_error and you’re told to try again in a minute.)
  • Missing required field: “I need the offer price and financing type before I can render the summary. What are they?”