Skip to main content
All Docs
FeaturesPurple PepperUpdated April 8, 2026

Offer Review, Amendment & Landlord Escalation

Offer Review, Amendment & Landlord Escalation

Available from v0.3.12

This feature gives agents a structured workflow to review incoming tenancy offers, request changes from tenants, escalate to landlords, and record final decisions — all with automated email notifications at each step.


How It Works

Offers move through a defined state machine. Agents drive transitions using the Action Panel on the offer detail page.

Status Flow

with_agent
  ├─► awaiting_amendments  ──► (tenant resubmits) ──► with_agent
  └─► sent_to_landlord
        └─► landlord_reviewed
              ├─► accepted   (terminal)
              ├─► rejected   (terminal, no resubmission)
              └─► awaiting_amendments

[any non-terminal status] ──► cancelled (terminal)

Step-by-Step

  1. An offer arrives at with_agent. The agent sees two primary action buttons: Request Amendment and Send to Landlord.
  2. Request Amendment → status becomes awaiting_amendments. The tenant receives an email containing the agent's notes and a link back to their offer form.
  3. When the tenant resubmits, the offer returns to with_agent and the cycle repeats.
  4. Send to Landlord → status becomes sent_to_landlord. The landlord receives a branded email with offer details and any agent notes.
  5. Record Landlord Decision → status becomes landlord_reviewed, recording the landlord's feedback.
  6. From landlord_reviewed, the agent can Accept, Reject, or Request Amendment again.
  7. Cancel is available from any non-terminal status at any point.

The Action Panel

The Offer Action Panel appears on the offer detail page for all non-terminal offers. It surfaces only the actions that are valid for the offer's current status.

Available Actions by Status

Current StatusAvailable Actions
with_agentRequest Amendment, Send to Landlord, Cancel
sent_to_landlordRecord Landlord Decision, Cancel
landlord_reviewedAccept Offer, Reject Offer, Request Amendment, Cancel
awaiting_amendmentsCancel
accepted / rejected / cancelled(no actions — terminal)

Using an Action

  1. Click an action button to expand its inline form.
  2. Enter any required notes or reason in the textarea (up to 2,000 characters).
  3. Click the confirm button (e.g. Send Amendment Request, Accept Offer).
  4. The page refreshes automatically on success.

Note: Some fields are required before you can confirm. Rejection requires a reason; amendment requests require amendment notes. Optional note fields are labelled accordingly.


Email Notifications

Every status transition that affects an external party triggers an automated, agency-branded email.

TriggerRecipientContent
Amendment requestedTenantAgent's amendment notes + link to offer form
Sent to landlordLandlordFull offer details + agent notes
Landlord decision recordedAgentInternal notification of landlord feedback
Offer acceptedTenantCongratulations notification
Offer rejectedTenantRejection notification with reason

Emails are dispatched via Inngest event-driven functions and rendered using branded HTML templates that inherit your agency's branding configuration.


Offer Detail Page Changes

  • Status description — A plain-language description of the current status is displayed below the status badge to give agents immediate context.
  • Transition timeline — A full history of every status change is shown, with timestamps and reasons, so agents can see at a glance what has happened to an offer.
  • Negotiation Thread — The comments section has been renamed "Negotiation Thread" to better reflect its role in the offer lifecycle.

API Reference

All offer workflow actions are exposed as tRPC mutations under the offer router.

offer.requestAmendment

mutation({ offerId: string, notes: string })
// notes are required

Transitions the offer to awaiting_amendments and sends the amendment email to the tenant.

offer.sendToLandlord

mutation({ offerId: string, notes?: string })

Transitions the offer to sent_to_landlord and sends the offer summary email to the property's landlord.

offer.recordLandlordDecision

mutation({ offerId: string, notes?: string })

Transitions the offer to landlord_reviewed, recording the landlord's feedback.

offer.acceptOffer

mutation({ offerId: string, reason?: string })

Terminal transition to accepted. Sends a congratulations email to the tenant.

offer.rejectOffer

mutation({ offerId: string, reason: string })
// reason is required

Terminal transition to rejected. No resubmission is possible. Sends a rejection notification to the tenant.

offer.cancelOffer

mutation({ offerId: string, reason?: string })

Terminal transition to cancelled. Available from any non-terminal status.


Audit & History

Every action performed via the offer router:

  • Writes a row to offer_status_transitions (previous status, new status, notes, timestamp, acting user)
  • Emits an audit log event for compliance and traceability

The transition timeline on the offer detail page reads directly from this history.