Architecture
PropSocket is a cache, not a proxy. We connect to your source systems on a schedule, normalize what we find into one Common Data Model, store it in the PropSocket cache, and serve that store over a REST API, webhooks, and scheduled exports. When you call PropSocket, you read our cache — you do not reach through to the source in real time. Internalize that one sentence and the rest of the system follows.
The pipeline
Data flows in one direction, left to right in your mental model and top to bottom here. Every stage runs on PropSocket's side except the source system and the consumer at the ends.
Your system of record. SOAP envelopes, undocumented quirks, per-vendor rate limits — all on the far side of PropSocket. Entrata is live today; additional integrations are built on request.
A per-source module that authenticates, fetches records, respects the source's rate limits, and maps raw fields into normalized CDM dicts. Non-standard fields land in custom_data.
Scheduled workers compare the latest fetch against what we already cached, write new and changed records, and mark records missing from the source as soft-deleted. Nothing is physically deleted.
The normalized store you actually read from. One row-isolated dataset per Organization. This is the source of truth for every API response and webhook payload.
Your apps consume via
You read the cache, not the source
There is no live passthrough. A GET /v1/units/{id} hits the PropSocket cache and returns in single-digit milliseconds — it does not open a SOAP session to Entrata and wait. That's the point: you get a fast, uniform, normalized API instead of the source system's latency, auth model, and pagination quirks.
The tradeoff is freshness. Your data is exactly as current as the last successful sync.
Cache freshness
The sync engine runs on a cadence set by your tier. Between runs, the cache is static — polling the API more often than your sync interval returns the same data and still counts against yourrate limit. Match your read cadence to your sync cadence, or react to webhooks instead of polling.
| Tier | Sync cadence | Worst-case staleness |
|---|---|---|
| Starter | Once daily | Up to ~24 hours behind the source |
| Growth | Customizable, up to every 4 hours | Up to ~4 hours behind the source |
| Scale | Customizable, up to every 1 hour | Up to ~1 hour behind the source |
| Enterprise | Customizable, up to every 15 minutes | Up to ~15 minutes behind the source |
Cadence per tier matches what's published on pricing. TheSYNC_COMPLETE webhook fires at the end of each run if you want a precise checkpoint for "the cache is now current as of this moment," and every record carries aps_synced_at timestamp for per-record freshness — see thesync engine.
What's behind the API
For the engineers who want to know what they're depending on:
- A durable normalized store — the CDM cache and system of record for reads.
- Scheduled sync workers — they fetch from each source on a cadence and reconcile the cache.
- A webhook dispatcher — it emits signed events the moment the sync engine sees a change.
- A fast read API — it serves
/v1/straight from the cache, never proxying to the source.
Reads and writes are handled by separate services, so heavy sync activity never slows down your API calls. You don't need to care which component answers your request — the contract is identical, which is why response shapes are documented against the API itself. Every tenant's data is stored in isolation, scoped end to end by organization_id (see multi-tenancy below).
Multi-tenancy
One Organization per customer is the tenant boundary. Every CDM record carries an organization_id, and every query is scoped to it — there is no path by which one Organization's key reads another's data. API keys are Organization-scoped, not user-scoped (authentication), and rate limits are pooled per Organization across all of its keys.
Next
See the shape of what's in the cache in theCommon Data Model overview, or go straight to afirst request.