AppFolio's Reports API team flagged Western Slope's account for call volume on 2026-10-27. It is our sync. This page shows every call we made for 30 days, per customer and per report, and proposes a cut of about two thirds with no visible change for renters or staff.
2026-10-28 morning · three changes live in production since ~1–3 AM Denver; measured below · Proposed — pending review
The headline. We make about 6,500 calls a day per customer, flat around the clock. AppFolio saw the tenant directory at ~250 a day at Western Slope; we measured 239. Two thirds of all calls come from three reports we pull every minute: guest cards, work orders and rental applications. The proposed plan keeps guest cards and work orders fast during the day, slows everything overnight, pulls the tenant directory once a day, and lands at about 2,200 a day (−66%).
One row per report, per customer. Measured = Western Slope's 30-day average per day. "Day" = 7 AM to 9 PM property-local; "night" = 9 PM to 7 AM. Today nothing slows down at night: 41% of calls land between 9 PM and 7 AM.
| Report | What it feeds | Today | Measured / day | Proposed (day / night) | After / day |
|---|---|---|---|---|---|
| Guest cards | New leads Clara answers | every 1 min | 1,379 | 1 min / 5 min | 960 |
| Work orders | Maintenance intake and status | every 1 min | 1,304 | 1 min / 5 min | 960 |
| Rental applications | Application status, co-signer linking | every 1 min | 1,395 | 5 min | 288 |
| Rent roll | Move-ins and move-outs, balances | every 5 min | 342 | 15 min / 1 h | 66 |
| Unit vacancy | Advertised rent Clara quotes; Camellia's availability source | every 5 min | 242 | 5 min where a property uses it (Camellia) / hourly elsewhere | 24 to 288 |
| Tenant directory | Residents' phone, email, co-signers, future move-ins | every 5 min | 239 | once a day (see section 7: needs a stored copy first) | 1 |
| Lease dates (tenant tickler) | Renewals, lease conversions | every 5 min + hourly history | 466 | hourly | 24 |
| Balances (3 reports) | What a resident owes | every 5 min each | 1,038 | hourly / once | 48 |
| Hourly and daily jobs | Renewal offers, charges, payments, books | hourly / daily | ~110 | unchanged | ~110 |
| Income statement (nightly metrics job) | 30-day income and spend figure per building | nightly, ~1 per building | 76 (corrected: 343 was log lines, most of them budget waits) | weekly or from stored charges | ~11 |
Measured = count of the sync Lambda's "GET …/reports/<report>.json" log lines for westernslopepm. One-minute jobs read below 1,440 because throttled ticks are skipped. The web app's hourly crons are not in these logs; by design they add at most a few hundred a day (estimate).
| Customer | Calls / day today (30-day avg) | Per unit per day | After plan A | Cut |
|---|---|---|---|---|
| Western Slope (234 units) | 6,471 sync + 76 metrics = 6,547 | 28 | ~2,200 | −66% |
| JP&Co (Camellia, Yale, Willows) | 6,680 | — | ~2,440 | −63% |
| Situs Group (connected 17 of 30 days) | 5,292 sync + 56 metrics | — | ~2,200 | −59% |
A. Slow the intervals and sleep at night (recommended). The table above. Three small changes: an off-hours rule per speed class in the sync Lambda, the tenant directory moved to a daily class, the metrics pull moved to monthly. No new mechanism. About −64%. Trade-off: a new resident's phone and email can be up to a day late in our records; a move-in shows up to 15 minutes later (AppFolio's own report lag is already 8 to 28 minutes).
B. A, plus re-pull the directory only when the rent roll shows a new tenant. Closes the one-day contact gap with one more trigger. Fede on Oct 1: "eventually consistent, don't over-engineer." Take B only if the gap bites.
C. A, with guest cards and work orders every 2 minutes in the day. About −76%. Trade-off: a lead's first reply can be up to 2 minutes later than today.
This is a fix to live behavior: no switch, live everywhere on merge, proven as below. The only owner step is picking A, B or C.
Clara never asks AppFolio live when a resident texts or calls. Balance, lease end, work-order status and who-is-this all come from our copy. The balance answer already treats anything under 24 hours old as current. Lease end comes from the rent roll, not the lease-dates report. Unit vacancy feeds the advertised rent Clara quotes to prospects at every property and is Camellia's availability source since Oct 2, so it stays, slower where no property uses the source. The tenant directory is what gives Clara a resident's phone and email, co-signers, and residents who signed but have not moved in yet.
How residents reach us, last 30 days (production conversation records; residents only):
| Western Slope | JP&Co | Situs | |
|---|---|---|---|
| Texts to Clara's number | 2 | 0 | 3 |
| Texts to the office's AppFolio line (our copy; JP&Co not copied) | 70 | — | 238 |
| Calls | 59 | 7 | 3 |
| Between 9 PM and 7 AM | 0 | 0 | 14 |
| Balance questions (threads or calls) | 6 | 0 | 4 |
| Lease-end questions | 7 | 0 | 1 |
| Maintenance | 30 | 2 | 20 |
So the three balance reports plus the lease-dates report, about 1,500 calls a day per customer, serve roughly ten questions a month per customer, and 3.7% of resident contact happens overnight. Prospects are the daytime traffic, and that is the guest-cards pull.
| Change | Why it is safe | Saves / day / customer | When |
|---|---|---|---|
| Rental applications: every minute → every 5 min | Nothing reacts to an application within a minute; Clara's status answer is already written for lag | ~1,150 | tonight, one PR |
| Balances (3 reports): every 5 min → hourly | Read only when a resident asks; product treats under-24h as current; nothing reads them at night | ~800 | tonight, same PR |
| Unit vacancy: hourly for accounts with no vacancy-source property (Western Slope, Situs); Camellia stays at 5 min | Checked live settings: it feeds the advertised rent Clara quotes, so it cannot stop. Needs a per-account last-pulled stamp, same mechanism as the day/night gate | ~260 (WS, Situs) | next, with the gate |
| 30-day income and spend figure: reuse the nightly answer across the moving window, or compute it from the charges we already store | About one request per building per night today; a PR to cache only the labor-rate piece was closed (saves ~1.5/day and risks a bad January reading) | ~65 (Western Slope) | next; changes what the daily chart means, so Fede's call |
| Guest cards and work orders: 1 min by day, 5 min overnight | Needs a property-local day/night gate per job, copied from the inbox-watch pattern | ~960 | next, needs a small design |
| Lease dates: 5 min → hourly | Two checks inside that job only run on minutes divisible by 5; a slower timer could silently never hit them. Fix that gate first | ~260 | next |
| Rent roll: 5 → 15 min | Move-in recognition widens by ~10 min on top of AppFolio's 8 to 28 min lag | ~190 | next, with the day/night gate |
| Tenant directory: once a day | Not simply a cadence change. A tick without directory rows records "no co-signers" and archives them, and loses the moved-in-early status. Needs a stored last-good copy fed on the skipped ticks | ~230 | design first |
Tonight's PR (applications, balances) takes Western Slope from ~6,550 to ~4,600 a day (−30%) with no visible change. The rest of plan A follows once the day/night gate exists, landing near ~2,200.
Baseline. Every figure below is against the Oct 1–22 average at Western Slope: 6,808 calls a day (CloudWatch, one line per request). Counts after Oct 23 are not a baseline; see the bug.
| Report | Decision | Share of Western Slope's calls | What changes for anyone | State |
|---|---|---|---|---|
| Guest cards | Stays every minute, day and night | 21% | nothing | locked |
| Work orders | Stays every minute, day and night | 21% | nothing | locked |
| Rental applications | every minute → every 5 min | 17% | an application is seen up to 4 min later | PR #23030 armed to merge |
| Rent roll | Stays every 5 min. The amount a resident owes comes from this report's past-due column (not from aged receivables, as section 7 assumed) | 5% | nothing | locked |
| Aged receivables, receipts, delinquency | every 5 min → hourly; the owed number is untouched | 15% | for up to an hour after a payment, the "last payment" line may name the previous one, with the hedge Clara already uses; a trigger that re-reads payments when a balance drops removes that | pending Fede: hedge or trigger |
| Lease dates (tenant tickler) | 5-min job → hourly, or deleted in favour of the hourly job that already pulls the same report over a wider window | 4% (the 5-min job's ~288 of 422) | a notice or a signed lease is seen up to an hour later; prospect-conversion checks read this data in-tick and are rewired either way | pending Fede: move or delete |
| Tenant directory | every 5 min → once a day, reused from a stored copy between pulls; a second PR re-pulls the moment the rent roll shows a new tenant | 4% | without PR 2, a new resident's phone is unknown to Clara for up to a day | PR 1 building |
| Unit vacancy | unchanged | 4% | — | dropped (not worth the digging) |
| Work orders slower 1–6 AM | rejected | 3.5% | — | dropped |
Net at Western Slope once everything above lands: about 40% fewer calls a day. Getting past that means touching guest cards or work orders, which Fede ruled out.
A budget change merged Oct 23 reserves part of each account's request budget per cadence class. In every 5-minute tick the balances job spends the budget first; the occupancies job then asks for the tenant directory, is refused by our own budget, and skips the whole tick, taking the unit-vacancy refresh with it. Measured Oct 26: occupancies ran 28 of 288 ticks at Western Slope, 35 at JP&Co, 241 at Situs. Directory refusals in the last 10 days: 4,914. Since Oct 23, new move-ins, contact changes and co-signers have reached Clara about one tick in nine at two customers. This is also why Andrew would see Western Slope's directory calls drop from ~285 to ~35 a day since Oct 23: a throttle, not a cut. Fix in progress (run occupancies before balances, or lower the reserve); it is a fix, so no switch, and it lands together with the daily directory so the directory count does not bounce back up.
Last 30 days of "new work order arrived" outcomes in the sync logs: 323 fetched detail with nobody paged (no handyman set up), 155 fetched detail with nobody paged (maintenance module off), 54 skipped (already closed or pre-onboarding backlog). Tech texts went only to Willows, our test property (1 sent, 3 held). No tenant acknowledgements were found in those logs. Fede kept work orders at every minute anyway; the day maintenance paging turns on at a customer is when this matters.
One CloudWatch Logs Insights query on the sync Lambda's log group: requests per database per report per day (the Oct 1–22 baseline came from the same query), beside the budget-refusal and skipped-tick counts. Expected after all of tonight's merges reach production: rental applications ≤288 a day, tenant directory ≤5 a day, occupancies skipped ticks near 0, guest cards and work orders unchanged near 1,440.
Live in production: applications every 5 min (PR #23030, merged 03:56Z), the starved 5-minute tick fixed (PR #23050, merged 04:44Z), tenant directory once a day from a stored copy (PR #23055, merged 06:59Z). The sync logs show all three in effect by 09:00Z (3 AM Denver). Every number below is the CloudWatch per-request count for the two full hours 11:00–13:00Z, scaled to a day, against the Oct 1–22 daily average (Situs: against Oct 27, its Oct 1–22 window was partial).
| Customer | Before (calls/day) | This morning (calls/day) | Cut |
|---|---|---|---|
| Western Slope | 6,808 | 5,160 | −24% |
| JP&Co / Camellia | 6,269 | 4,716 | −25% |
| Situs Group | 6,672 (Oct 27) | 5,088 | −24% |
Per report, Western Slope (calls/day, before → this morning): rental applications 1,444 → 288; tenant directory 285 → 0 since 08:00Z after one live pull per account at 07:00Z (the stored copy served 12 ticks an hour since); guest cards 1,423 → 1,440 and work orders 1,423 → 1,464, unchanged by design; rent roll 356 → 312; receipts, aged receivables, delinquency ~350 each → 312–336; lease dates 422 → 312; vacancy 261 → 288.
The starvation bug is gone. Our own budget refused 420 requests across the three accounts between midnight and 09:00Z, then 6 in 09–11Z and 4 in 11–13Z. Occupancies ticks skipped for throttling: 61 at Western Slope and 52 at JP&Co before 09:00Z, none after. New move-ins and contact changes reach Clara every 5 minutes again.
Why 24% and not the ~40% target: the remaining approved cuts (balance side reports hourly, lease dates) wait on Fede's two picks in section 8 and are not built. Guest cards and work orders, 43% of the total, stay at every minute by decision.
Proof query (CloudWatch Logs Insights, log group /aws/lambda/propflow-appfolio-sync-prod):
fields @timestamp | filter @message like /GET https:\/\/[a-z0-9-]+\.appfolio\.com\/api\/v1\/reports\// | parse @message /GET https:\/\/(?<db>[a-z0-9-]+)\.appfolio\.com\/api\/v1\/reports\/(?<report>[a-z_]+)\.json/ | stats count(*) as calls by db, report, bin(1h)
Refusals: filter account budget exhausted; skipped ticks: filter portfolio fetch throttled; directory reuse: filter tenant_directory from store / tenant_directory pulled live.
Fede gave the go after three side-effect investigations; both changes merged with no switch.
| Change | PR | Before | After |
|---|---|---|---|
| Balance side reports (aging, payments, delinquency) | #23212 | every 5 min with the rent roll | hourly, plus an immediate re-pull when anyone's owed amount drops; aging carried forward with an as-of stamp; the "may not be current" hedge clears after a confirming pull; rent roll still every 5 min |
| Lease dates | #23213 | a 5-minute pull of the tenant tickler report | deleted; the hourly history job already writes the same fields; signed-applicant promotion reads the stored signed date; onboarding import uses the hourly job; PM countersign reminder starter runs hourly, once per account, only for companies opted in (JP&Co only). It had been silently off since Sep 9 (minute gate). |
| Topic | Finding |
|---|---|
| Balances | 5 Clara phone lookups + 24 AppFolio inbox texts at Western Slope and Situs (mirror starts Sep 29): 0 of 29 would have gotten a different answer hourly. Every "I paid, why does it still show" case was AppFolio posting late (105 min to 2 days). |
| Lease dates | An hour's delay touches notice-to-vacate reaching turnover/renewal and dashboard move counts; Fede accepted. |
| Directory daily | 0 real misses in 30 days. A pull-time pin before Nov 1 (31 move-ins Nov 1–2) is still parked for Fede. |
| Check | Result |
|---|---|
| tenant_tickler calls | 1 per database at the 18:21Z hourly tick only; none on 5-min ticks (before: 1 per database per 5 min) |
| Balance side reports | one full pull per account at 18:28–18:31Z, then rent roll only (1 request instead of 4 per tick); stamp rows written for all three accounts |
| Errors / Sentry | 0 error-level lines since either deploy; 0 new Sentry issues |
| Budget refusals / skipped ticks | inside the day's normal range |
| 15 sampled lease rows (5 per customer) | unchanged after the hourly tick |
| Countersign reminder | started at Camellia for a lease ready since Oct 25 (first in 7 weeks); other companies log "not opted in, no robot walk" |
| Collections page, Western Slope and Situs | loads, aging filled, totals match, tenant detail opens (screenshots in session) |
| Clara by text at Willows | balance $1,615.50 unhedged = stored row; lease end Jan 16 2027 = lease row (Willows rows are hand-loaded, so this proves the read path only) |
| Not yet seen | second hourly pull (~19:25Z), carried aging, hedge clearing: no balance changed since deploy |
| Original | After morning (−24%) | After round two |
|---|---|---|
| ~6,800 | ~5,160 | ~4,050 (−40% vs original) |
Estimates until the next CloudWatch count.
leasing:lease-terms-hydrate refused 228×/day at jpco.