Back to BlogIndustry Guides

A Maintenance Ticketing SaaS for Property Managers

Rupak Amin

Founder & Lead Engineer, RAITHub

8 min read

A maintenance ticketing SaaS for property managers is a multi-tenant product, not one landlord's tracker. Each firm's tickets, properties and vendors must be fully isolated, SLA timers must escalate on time without anyone watching, vendors need a limited view, and usage has to be billed. Build the escalation engine on scheduled jobs, isolate every firm in the database, and test that no ticket goes quiet.

If you would rather have it built and tested for you, see how RAITHub would build this below. First, what makes this a SaaS rather than a single-firm tool.

How is a maintenance SaaS different from one landlord's tracker?

A single landlord routing jobs to their own contractors is covered in a maintenance request system that routes jobs to contractors. A SaaS adds four things that change the architecture: multi-tenancy (many firms on one platform, none seeing another's data), SLAs (contractual response and resolution times that escalate automatically), a vendor side (external contractors with their own accounts and a deliberately narrow view), and billing (you charge the firms). Each is a place where a naive build leaks data or drops a ticket.

What does the data model look like?

EntityHoldsScoped to
Firm (tenant)The property-management company paying for the SaaSitself
Property / unitWhat is being maintainedfirm
TicketThe request, its priority, SLA target and statefirm
VendorAn external contractor, with trades and areasfirm (or shared, invited per firm)
AssignmentWhich vendor is on which ticket, and whenfirm
SLA policyResponse and resolution targets per priorityfirm

Give every firm-scoped table a firm_id and enforce it in the database, so one firm can never read another's tickets or vendors. The isolation pattern and the CI check that proves it are in multi-tenant property management SaaS isolation.

How do SLA timers and escalation work?

An SLA is a promise with a clock: respond within X, resolve within Y, by priority. The danger is a ticket that no one escalates because no human was watching. Compute each ticket's SLA target when it is created, then run a scheduled job that finds tickets past their target and escalates them, reassign, notify a manager, bump priority, without anyone needing to remember.

-- Tickets carry their SLA deadline so a scheduled job can find breaches.
CREATE TABLE tickets (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  firm_id     uuid NOT NULL,                    -- tenant key
  priority    text NOT NULL,                    -- emergency | urgent | routine
  state       text NOT NULL DEFAULT 'open',
  respond_by  timestamptz NOT NULL,             -- SLA response deadline
  resolve_by  timestamptz NOT NULL,             -- SLA resolution deadline
  created_at  timestamptz NOT NULL DEFAULT now()
);

-- Run every few minutes: the breach query the escalation job uses.
SELECT id, firm_id, priority
FROM tickets
WHERE state IN ('open', 'assigned')
  AND respond_by < now();            -- past the response SLA, not yet responded

Make the escalation job idempotent: if it runs twice it must not send two alerts or double-escalate. The scheduled-job pattern, and running several reliably, is the kind PropDesk runs daily.

What should a vendor see, and what should they never see?

A vendor sees the tickets assigned to them, the property address they need and the job details, and nothing else: not the firm's other tickets, not other vendors, not costs they are not party to. This is a role boundary enforced in the database, not hidden in the UI. Model it with permissions (designing SaaS authorization) and test that a vendor requesting a ticket outside their assignments gets a 404.

How do you bill firms for the SaaS?

Pick a model and meter it honestly: per managed unit, per active ticket, or a tier. Whatever you charge for, record the usage as it happens and reconcile it against what you bill, so an invoice can always be explained. Treat the billing webhook as applied-exactly-once, even if it arrives twice; the reasoning is in testing payments and webhooks end to end.

How do you test a maintenance ticketing SaaS?

The highest-value tests are the ones that prove a ticket cannot be lost and a firm cannot see another's data.

// tests/maintenance/sla-escalation.spec.ts
import { test, expect } from 'vitest'
import { runEscalationJob } from '@/jobs/escalate'
import { seedTicket, advanceClockPast } from './helpers'

test('a ticket past its response SLA is escalated exactly once', async () => {
  const ticket = await seedTicket({ priority: 'urgent' })
  await advanceClockPast(ticket.respond_by)

  await runEscalationJob()
  await runEscalationJob() // running twice must not double-escalate

  const events = await ticket.escalations()
  expect(events.length).toBe(1)
})

Add a cross-firm isolation suite (one firm cannot read another's tickets), a vendor-view test, and a role matrix. Shape the whole suite like any SaaS in the test pyramid for a SaaS.

Buy, build or hire?

OptionWhat you getChoose this when
A generic helpdesk toolTickets and SLAs, but not property-awareYou manage one firm and don't need vendors or units modelled
Maintenance inside a property platformTickets bundled with the rest of the suiteYou use that whole platform and its maintenance fits
A custom maintenance SaaSMulti-firm isolation, SLA escalation, a vendor side and billing, as a product you sellYou are building a SaaS for property managers to pay for
A managed QA team on your buildSLA, isolation and vendor suites gated in CIYou have the product but "no ticket is lost" isn't proven on every build

How long does it take to build yourself?

A first release with tickets, the SLA escalation job, per-firm isolation and a vendor view is in the 4 to 6-week fixed-scope range; billing and a full vendor marketplace push it into 6 to 12 weeks, in phases. The main risk of doing it yourself is the escalation job: if it is not idempotent and not tested, it either spams alerts or silently stops, and a ticket sits untouched for two weeks.

Why RAITHub for this

RAITHub built PropDesk, property-management SaaS with four roles, maintenance routing and five daily automation jobs, with 1,024 tests, and enforces per-tenant isolation on Sundor Skin (530+ tests). The multi-tenant build sits inside PropTech software development and the SaaS development service. See the real-estate industry page.

When you don't need us

  • You manage one firm, not a product. A single-firm maintenance tracker or a generic helpdesk may be enough.
  • Your current platform's maintenance module fits. Use it.
  • Your procurement requires a SOC 2 or ISO 27001 vendor. RAITHub is not certified, though it builds the controls your auditor tests.

How RAITHub would build this

  • Scope: a multi-tenant ticket model with per-firm isolation, an SLA and escalation engine on scheduled jobs, a narrow vendor view, roles, and metered billing.
  • Timeline: 4 to 6 weeks at a fixed scope for a first release; billing and a vendor marketplace in the 6 to 12-week range, in phases.
  • What you receive: the SLA, isolation and vendor suites gated in CI, runbooks, the product on accounts you own, IP assigned to you and an NDA as standard.
  • Ways to buy it: a fixed-scope build, a dedicated monthly team, or a QA plan if you only need the maintenance test suite.
  • Next step: a free 15-minute technical audit, then a fixed written quote.

See the QA as a Service page, or book the free 15-minute audit.

Documentation checked on 10 October 2026.

Frequently asked questions

What is a maintenance ticketing SaaS for property managers?

A multi-tenant product that many property-management firms pay to use for logging, assigning and tracking maintenance jobs. It differs from one landlord's tracker because it isolates each firm's data, enforces contractual SLAs, gives vendors a limited view, and bills the firms for usage.

How do SLA timers and escalation work?

Each ticket gets a response and resolution deadline when it is created, by priority. A scheduled job runs regularly, finds tickets past their deadline, and escalates them automatically, reassigning, notifying a manager or raising priority, so no ticket depends on a human remembering to check.

How do you keep one firm from seeing another firm's tickets?

Give every firm-scoped table a firm id, scope every query to it, and back it with PostgreSQL row-level security so a missed filter cannot leak data. A CI check fails if a firm-scoped table has no policy, and an isolation suite tries to read another firm's tickets and expects a 404.

What should a vendor be able to see?

Only the tickets assigned to them, with the property address and job details they need to do the work. Not the firm's other tickets, other vendors, or costs they are not party to. That boundary is enforced in the database and tested, not just hidden in the interface.

How should the escalation job avoid sending duplicate alerts?

Make it idempotent: record that a ticket has been escalated so a second run of the job does nothing further. A test seeds a breached ticket, runs the job twice, and asserts exactly one escalation, which catches the duplicate-alert bug before customers do.

maintenance ticketing saasproperty managementmulti-tenant saassla escalationvendor dispatchproptech

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.