Sites API reference
Every Sites endpoint, generated from the OpenAPI document at /openapi/sites.json.
The website delivery API. Everything a Next.js property website or centralized leasing website reads from Resi, scoped to one website. It is separate from the property-centric /api/v1, which is unchanged.
Authentication. Every request needs Authorization: Bearer <token>. A token is scoped to exactly one website (website:{id}:deliver, or website:{id}:preview for draft content) and must belong to the website's account; an account API token, whose ability is the wildcard *, is refused. Call it from the site's server; the token must never reach a browser.
Which website. Resolved from the Host header, or from X-Resi-Website when Host is meaningless (CI builds). The website never appears in the URL. The resolved website and the token's website must agree, otherwise 403.
Addressing. Properties, floor plans and units are addressed by slug and found only among the website's own enabled properties. Anything else is a 404 identical to a record that does not exist. UUIDs are not accepted in paths.
Envelope. Every success is {data, meta}. Keys are snake_case. Lists add meta.pagination. Errors are {message} and, for validation, {message, errors}.
Caching. Every GET sends an ETag and honours If-None-Match with 304. Cache-Control is private, no-cache. meta.cache.tags names what the payload was built from and meta.cache.ttl suggests how long to hold it. Resi sends a signed cache-clear webhook naming the tags that changed.
Cache-clear webhook. When data a website rendered changes, Resi POSTs to the site (default https://{primary domain}/api/resi/cache, or the URL in the website's cache_webhook_url setting; https to a public host only, and a redirect is never followed) with X-Resi-Event: cache.invalidate and a JSON body: {"event": "cache.invalidate", "website_id": "...", "tags": ["inventory:..."], "paths": [], "timestamp": 1789760000}. Only a site built to receive it is sent one: a site whose provisioning wrote it RESI_CACHE_WEBHOOK_SECRET (every site scaffolded from the current template), or one whose cache_webhook_url setting names a receiver. Sites on earlier templates are never sent it. Verify it before acting: X-Resi-Signature is sha256= followed by the HMAC-SHA256 of the raw request body, keyed with the site's RESI_CACHE_WEBHOOK_SECRET (written to the site's environment at provisioning; unique per website). Reject a body whose timestamp is more than a few minutes old, since the timestamp is inside the signed bytes precisely so a replay cannot refresh it. Then revalidate every cached response carrying one of tags. Answer 2xx; anything else is retried up to five times with backoff. Changes within about fifteen seconds are sent as one webhook. A change Resi does not detect is picked up when meta.cache.ttl runs out.
Tags. site, paths, property:{id}, inventory:{property_id}, entries:{type}, integrations:{property_id}, lead-sources:{property_id}, forms:{property_id}.
Filtering. List endpoints accept documented filters, sort (- prefix for descending, comma-separated) and page / per_page. A value that cannot be applied is a 422, never an ignored filter.
Compatibility. Additive changes ship continuously: new endpoints, new optional parameters, new keys. Removing or retyping a key is a breaking change and needs an ADR.
Endpoints
Bootstrap
What a build reads first.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/site | Site manifest |
GET /api/sites/v1/paths | Renderable paths |
GET /api/sites/v1/resolve | Resolve a path |
GET /api/sites/v1/groups | Group sets |
Content
Content entries.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/content-types | Content types |
GET /api/sites/v1/entries/{type} | List entries of a content type |
GET /api/sites/v1/entries/{type}/{slug} | One entry |
Properties
The website's properties.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/properties | List properties |
GET /api/sites/v1/properties/{property} | One property |
GET /api/sites/v1/properties/{property}/neighborhood | Neighborhood |
GET /api/sites/v1/properties/{property}/reviews | Reviews |
GET /api/sites/v1/properties/{property}/instagram | Instagram feed |
Inventory
Floor plans, units and availability across the website's properties.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/floor-plans | List floor plans |
GET /api/sites/v1/floor-plans/{floorPlan} | One floor plan |
GET /api/sites/v1/units | List units |
GET /api/sites/v1/units/{unit} | One unit |
GET /api/sites/v1/units/{unit}/price-matrix | Unit price matrix |
GET /api/sites/v1/availability | Availability feed |
GET /api/sites/v1/unit-types | Unit types |
GET /api/sites/v1/facets | Search facets |
Attribution
Lead sources and the rules that pick one for a visit.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/lead-sources | Lead sources for every property |
GET /api/sites/v1/properties/{property}/lead-sources | Lead sources for one property |
Integrations
The third-party tools a property's pages embed.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/integrations | Integrations for every property |
GET /api/sites/v1/properties/{property}/integrations | Integrations for one property |
Conversion
Forms, leads, tours and analytics events.
| Endpoint | Summary |
|---|---|
GET /api/sites/v1/forms | List forms |
GET /api/sites/v1/forms/{form} | One form |
POST /api/sites/v1/forms/{form}/submissions | Submit a form |
POST /api/sites/v1/tours/availability | Tour availability |
POST /api/sites/v1/tours/reservations | Reserve a tour |
POST /api/sites/v1/events | Record an analytics event |
POST /api/sites/v1/source-observations | Record a source observation |
Last updated on
Generating types
Generate TypeScript types for Sites API responses from the OpenAPI document.
Site manifest GET
Everything site-wide a build needs in one call: domains, tracking, redirects, URL patterns and a card per property (at most 500; `meta.properties` counts them). Tags: `site`, plus `property:{id}` and `inventory:{id}` for each property.