Skip to content

Multi tenant isolation

Fredrik Dettner edited this page Oct 12, 2026 · 3 revisions

Multi-tenant isolation

Your Fastighetsbenchmark data is yours alone. This is the single most important security guarantee in the Partner API v2, and it is enforced at the data layer — not in application code that a future change might forget.

The guarantee

Every API key resolves to exactly one SedisCustomer (your organization). For tenant-scoped resources, the database query is filtered to that customer by default — there is no code path that returns another customer's rows. This is a default-deny posture: a new endpoint cannot accidentally leak cross-tenant data by omitting a WHERE clause, because the filter lives on the data context itself.

Tenant-scoped resources:

  • /fastighetsbenchmark/property-units
  • /fastighetsbenchmark/samlingar
  • /fastighetsbenchmark/jamforelseobjekt
  • /fastighetsbenchmark/comp-data

404, not 403

If you request a specific sedisId that exists but belongs to another customer, you receive 404 Not Found — exactly the same response as for a sedisId that does not exist at all.

# A sedisId you don't own (or that doesn't exist) → identical 404
curl -i -H "X-Api-Key: $SEDIS_API_KEY" \
  "https://api.sedis.se/v2/fastighetsbenchmark/property-units/SOME-OTHER-TENANTS-ID"
# → HTTP/1.1 404 Not Found

This is deliberate. A 403 Forbidden would confirm the resource exists and leak the fact that some other customer owns it. 404 reveals nothing. The same applies to list endpoints: they are filtered to your rows, so another customer's data simply never appears in data — you cannot page or filter your way to it.

Shared reference data

Some Fastighetsbenchmark data is Sedis-curated and shared across all customers (read-only). These resources are not tenant-filtered — every key sees the same rows:

  • /fastighetsbenchmark/reference-zones — external benchmark datasets curated by Sedis (Nils Holgersson, Cushman & Wakefield, SEPREF, Forum, …).
  • /fastighetsbenchmark/parameters — parameter metadata.

Note: Sedis-owned SedisObjekt aggregates are also reference data internally, but are not a fetchable resource — you reach them only as the source of your own clones, via the tenant-filtered clone lineage (below).

Bolagsanalys (/bolagsanalys/...) is entirely reference data — companies, parameters, and figures are the same for every customer, with no tenant filtering at all.

Clone lineage is tenant-filtered too

When a shared SedisObjekt is cloned into comparison zones (Jämförelseobjekt) by multiple customers, both directions of the clone lineage are filtered to your own rows only:

  • belongsToJamforelseobjekt (reverse, on a property-unit) lists only your clones — if Customer A and Customer B both cloned the same SedisObjekt, A sees only A's clone reference and B sees only B's.
  • containsPropertyUnits (forward, on a Jämförelseobjekt) lists only your property-units in the source SedisObjekt — even though the shared SedisObjekt may contain other tenants' units, A never sees B's units and vice versa.

The cross-tenant references never leak in either direction. See The Comp Composite & clone lineage.

Writes are tenant-stamped

When you create data (POST /samlingar, POST /property-units, POST /comp-uploads), the owning customer is taken from your API key, never from the request body. You cannot write into another tenant — the request bodies do not even carry an owner field.

Every write is scoped to your own data the same way reads are:

  • PUT property-units/{sedisId} on another customer's property unit is 404 — also with If-Match (a 412 would confirm it exists).
  • PATCH and DELETE on another customer's property unit, and its pending-changes, are 404 too (since 2.4.0).
  • An upload row naming another customer's sedisId gets the same unknownSedisId as one that does not exist.
  • Property-unit names are unique per customer: another customer may use the same name, and the 409 for a name in use only ever points at your own property unit.
  • Idempotency-Key replays are scoped to your customer.

See Writing data.

Clone this wiki locally