The thing nobody puts in the brochure

Entrata's API is technically REST. You will hit HTTPS endpoints. You will get JSON back. These are both true, and both misleading. What you're actually talking to is a JSON wrapper around a SOAP-shaped envelope, and the wrapper does not protect you from the envelope's preferences about how the world should work.

Every request expects a top-level auth object containing your username and password — not a token, the actual credentials — plus a method name and amethodParams object whose shape depends on the method. Responses come back nested two or three levels deep inside a response.result tree, with field names that vary by entity type and sometimes by which method you called. The first time you fetch leases and the first time you fetch residents, you will write different code to unwrap the result, and that's because they have different shapes. That's the kind of API this is.

None of this is in the marketing copy. All of it is in your terminal an hour into the integration.

Authentication: a credential, not a token

You get a username and password from your Entrata customer's admin. You put them in every request body. That is the authentication. There is no OAuth, no rotating bearer token, no short-lived JWT. The credential is long-lived and lives in your secret manager forever, and rotation is something your customer does in their Entrata admin console — which means rotation requires a coordination meeting, not an API call.

Practical consequences: if you're building a multi-tenant integration that serves many Entrata customers, you are storing many sets of long-lived credentials in your secret manager. Treat that with the seriousness it deserves. Use per-customer secrets, scope access to the integration worker only, and audit reads.

Also: the permission scope on the API user matters more than the docs admit. The same endpoint can return a populated list of properties or an empty array depending on whether the API user has the right entity-level permissions set inside Entrata. The API will not tell you the difference. You will assume your code is broken; it isn't. The API user is underpowered. Set the permission, retry, get data.

Pagination: it exists, and it does not

Some endpoints paginate. Some don't. The ones that do paginate use a method-specificpage and pageSize mechanism that lives insidemethodParams. The ones that don't paginate cheerfully hand you the full dataset in a single response, which is fine for properties (you probably have dozens) and less fine for leases (you probably have tens of thousands).

There is no Link: next header. There is no hasMore in the response envelope. You compute "is there another page?" by checking whether the count you got back equals the page size you asked for, and you keep going until it doesn't. This is fine. It is also exactly the kind of thing that breaks subtly when Entrata changes the default page size on their end, which has happened.

Edge case: empty pages in the middle

On a few endpoints — and the set is not documented — you can get an empty page in the middle of a paginated sequence and then a non-empty page after it. If your loop exits on the first empty response, you will silently miss data. Loop on response.resultbeing absent, not on the result being empty.

Dates, times, and the timezone you don't have

Entrata returns dates as MM/DD/YYYY strings most of the time and asYYYY-MM-DD some of the time and as ISO-with-no-timezone-suffix occasionally. Datetimes come back in the property's local time, with no offset and no zone identifier. If your portfolio crosses time zones — and it probably does — you cannot correctly compare two timestamps from two properties without first looking up each property's timezone in the property record.

We standardize all of this to UTC ISO 8601 datetimes and YYYY-MM-DD dates before anything lands in the CDM. Otherwise the first time you write a "leases signed today" query, you will write it wrong.

Money, and the float you must never have

Entrata returns money as decimal numbers in JSON. JSON parsers in many languages will happily turn 1250.00 into a float. Floats are not money. Run that through enough additions, comparisons, and rounding operations and you will silently produce balances that drift by cents — which is the kind of bug that nobody notices until a resident calls in about a charge that's off by a penny.

Parse money as integer minor units the moment it crosses the boundary. PropSocket stores every money field as integer cents plus a paired currency field. The CDM shape:

{ "amount": 125000, "currency": "USD" }  // $1,250.00

Use this pattern even if you don't use PropSocket. The decision to store money as a float is a decision you cannot easily reverse three years later.

Soft deletes, hard surprises

When a record disappears from Entrata's response — a lease that was there yesterday, a resident who was there last week — it is rarely because the record was deleted. More often the record was marked inactive, or moved to a different status, or had a permission change that removed it from your API user's view, or got merged with another record by a property manager who didn't tell anyone.

If your integration treats "not in today's response" as "delete this from my database," you will lose data. Often. Sometimes the record reappears the next day. Sometimes the permission gets fixed three weeks later. By then the analytics dashboards have an unexplained gap and the resident's history is broken across two records.

Use soft deletes — set a deleted_at timestamp instead of removing the row. PropSocket does this for you and keeps the historical record intact. If you're rolling your own, the rule is: never physically delete a synced record. Ever.

What happens when Entrata is having a bad afternoon

Entrata's API has outages. They are rare. They are not zero. When one happens, you will see some combination of: requests timing out, requests returning HTTP 500, requests returning HTTP 200 with an error payload nested somewhere insideresponse.result, and requests returning HTTP 200 with stale data because the read replica is behind. The HTTP layer does not consistently signal the failure mode. You have to inspect the body.

Useful defaults:

When Entrata is having a bad day, PropSocket queues writes, retries on a sane schedule, emits SYNC_COMPLETE webhooks only after a clean run, and surfaces the partial-failure mode in the dashboard. You don't have to build that. You can.

The XML-shaped fields hiding inside the JSON

A few Entrata endpoints — and again, the set is not exhaustively documented — return fields whose values are XML strings inside a JSON response. You will get back a JSON object containing a string that, on inspection, is <Address>...</Address>. You will need to parse the XML to get at the data. The first time this happens you will assume you got a corrupted response. You did not. That's the API.

Build your parser to be resilient: if a string field starts with <, try the XML path; otherwise treat it as plain. Don't crash on the JSON parse step — that's the wrong layer to fail at.

Webhooks: a quick word about what doesn't exist

Entrata does not push you data. There is no native webhook surface. If your application needs to react to a lease being signed within minutes, you have two choices: poll the API on a tight cadence (and pay the rate-limit cost), or run a sync engine that polls on sensible cadence and emits its own webhooks to your endpoints.

We do the latter. Every change PropSocket's sync engine detects emits a signed HTTPS event to a URL you control, with HMAC-SHA256 signature verification and at-least-once delivery semantics. Thewebhooks page walks through the full event catalog. The point isn't that PropSocket is magic; it's that webhooks were never on Entrata's menu and you had to build them yourself.

What you can stop maintaining once you use PropSocket

This is the part of the post that will sound like an advertisement. It's also the part that's true. If you adopt PropSocket as your Entrata integration layer, here's the code you stop owning:

That's not nothing. That's a small engineering team's quarter, give or take. You get to spend that quarter on the product your customers actually pay you for.

If you build it yourself anyway

Some teams will, and there are good reasons to. Maybe Entrata is the only PMS you'll ever support. Maybe you've already paid down the integration debt and the code is stable. Maybe your write-back requirements are deep enough that PropSocket's read-first MVP isn't a fit yet.

If that's you, the take-aways from this post are:

Normalize at the boundary. Store money as integers. Store timestamps as UTC. Never physically delete synced rows. Loop pagination on response shape, not on length. Inspect response bodies on every failure. Build a webhook layer because the source won't.

Do those six things and you've sidestepped roughly 80 percent of the silent bugs that Entrata integrations ship with. The other 20 percent is the part where the API changes under you between sprints, and that's a problem you can't solve with code — only with a sync engine that watches and adapts.

Either way: good luck. Reply to /contact if you want to compare notes. We're happy to talk about the parts of Entrata that aren't on this page yet.