Bootstrap, routing & content
The site manifest, every renderable path, resolving a URL, content types and entries, and group sets.
These are the endpoints a build reads first. Between them they answer: what is this site, which URLs does it have, and what serves each one?
The site manifest
GET /site — everything site-wide in one call. Tags: site, plus property:{id} and inventory:{id} per property.
| Key | Holds |
|---|---|
website | id, name, type (property or portfolio), platform, status, locale, environment (production or preview) |
domains[] | hostname, is_primary, managed_by |
tracking | Account-level tracking ids, for example gtm_id. A free-form map; {} when none |
redirects[] | from, to, status |
routing | The URL patterns; see below |
properties[] | A card per enabled property, in the website's order — the same card GET /properties returns. At most 500; meta.properties gives { total, listed }, and a larger portfolio reads the rest from GET /properties |
theme.tokens | Design tokens, or null |
search | The site's search: app_id, search_key (search-only, safe to publish) and indices (properties, units, each a name or null). By default this is Resi-managed search, whose key is limited to this site's indices and domains. A website set to search its account's own Algolia connection gets that connection's application, search-only key and indices instead. null until the website's search is provisioned or its connection can be searched, or where it has none |
URL patterns
"routing": {
"patterns": {
"property": "/property/{slug}",
"property_archive": "/properties",
"floor_plan": "/floor-plan/{slug}",
"floor_plan_archive": "/floor-plans",
"unit": "/unit/{slug}",
"unit_archive": "/units"
},
"uniform": true
}The segments come from the account's website settings, with the defaults above. uniform is false when any property overrides a segment; when it is, do not build URLs from the patterns — use each record's own path, which is always right. On a property website the property's path is /. patterns is null for a website with no properties.
Every property, floor plan, unit and entry carries a ready-made path. Prefer it over assembling URLs yourself.
Every renderable path
GET /paths — for generateStaticParams and the sitemap. Tag: paths.
| Parameter | |
|---|---|
type | One or more of property, floor_plan, unit, entry, comma-separated. Unknown is a 422 |
page, per_page | Default 500, ceiling 2000 |
{
"data": [
{ "path": "/property/contract-property", "type": "property", "slug": "contract-property", "property_slug": "contract-property", "content_type": null, "updated_at": "2026-01-15T12:00:00+00:00" },
{ "path": "/team/ada", "type": "entry", "slug": "ada", "property_slug": null, "content_type": "team", "updated_at": "2026-01-15T12:00:00+00:00" }
],
"meta": { "pagination": { "total": 4, "page": 1, "per_page": 500, "last_page": 1 }, "cache": { "tags": ["paths"], "ttl": 3600 } }
}Paths come in a fixed order — properties, floor plans, units, entries — so paging is stable. Grouped floor plans appear once, under their primary. updated_at is the sitemap's lastmod.
Resolving a path
GET /resolve?path=/team/ada — what serves a URL the build did not generate. Checked in this order: content entry, property, floor plan, unit, redirect. A path something occupies always wins over a redirect.
data.type tells you which branch you got:
type | Alongside it |
|---|---|
entry | entry — the full entry |
property | property: { id, slug, name } — fetch it from GET /properties/{slug} |
floor_plan | property and floor_plan references — fetch from GET /floor-plans/{slug} |
unit | property and unit references (name is the unit number) — fetch from GET /units/{slug} |
redirect | redirect: { "to": "/new", "status": 301 } |
{ "data": { "type": "redirect", "path": "/old", "redirect": { "to": "/new", "status": 301 } }, "meta": { "cache": { "tags": ["site"], "ttl": 3600 } } }Nothing there is a 404 you can branch on:
{ "message": "Nothing serves this path.", "type": "not_found", "path": "/nothing-here" }Content types
GET /content-types — the content types this website renders, with the fields that shape each one's entries. Tag: site. Ordered by plural name; not paginated.
A content type is a shape of content — team member, blog post, neighbourhood guide — defined by Resi staff. An entry is one record of that shape. A type is listed when it belongs to the website's account, is enabled, and is either account-wide, authored for this website, or a library type this website has opted into.
{
"key": "team",
"singular": "Team member",
"plural": "Team members",
"scope": "account",
"url_pattern": "/team/{slug}",
"template": "default",
"schema_type": "Person",
"expiry_field": null,
"fields": [
{ "key": "name", "label": "Name", "type": "text", "required": true, "help": null, "options": null, "fields": null, "conditions": null },
{ "key": "role", "label": "Role", "type": "select", "required": false, "help": null, "options": { "agent": "Leasing agent", "manager": "Manager" }, "fields": null, "conditions": null },
{ "key": "links", "label": "Links", "type": "repeater", "required": false, "help": null, "options": null, "conditions": null,
"fields": [{ "key": "url", "label": "URL", "type": "url", "required": true, "help": null, "options": null, "fields": null, "conditions": null }] }
]
}| Key | |
|---|---|
key | What /entries/{type} accepts |
scope | account (every website in the account), site (this website only) or library (shared, opt-in per website) |
url_pattern | The pattern this website uses. A library type lets each site choose its own — /blog/{slug} on one, /journal/{slug} on another. null when entries have no page of their own and are only embedded |
template | The template this website renders the type with; default unless it chose another |
schema_type | The schema.org type behind each entry's schema JSON-LD |
fields[] | What an entry's data holds, keyed by fields[].key |
Field type is one of text, textarea, rich_text, number, boolean, date, datetime, select, multi_select, email, url, phone, image, images, file, video, property, property_group, entry_reference, repeater, group, colour, markdown, json. Render the ones you know and ignore the rest; new types may be added.
options— forselectandmulti_select: stored value → label. An entry'sdataholds the stored value.fields— forrepeater(a list of items) andgroup(one nested object): the nested definitions.conditions— the field applies only when siblings at the same level match:{ "role": "manager" }, or{ "role": ["manager", "agent"] }for any of several.
Use it to generate types for data, or to render a type generically without knowing it in advance.
Content entries
{type} is the content type's key (team), never an id.
GET /entries/{type} — tag entries:{type}.
| Parameter | |
|---|---|
term | Term slugs or ids, comma-separated; an entry matching any is returned |
property | A property slug; entries written for that property |
page, per_page | Default 50, ceiling 200 |
meta.content_type describes the type: key, singular, plural, url_pattern, schema_type.
GET /entries/{type}/{slug} returns { "type": "entry", "path", "entry" } — or { "type": "redirect", … } when the slug was renamed, so old links keep working.
{
"id": "01a0b9f5-b5e5-73b5-b172-06d40e30f8b6",
"slug": "ada",
"path": "/team/ada",
"status": "published",
"content_type": "team",
"property_id": null,
"data": { "name": "Ada Lovelace", "bio": "Community manager." },
"seo": {},
"terms": [],
"schema": { "@context": "https://schema.org", "@type": "Person", "name": "Ada Lovelace", "url": "https://www.example-apartments.com/team/ada" },
"published_at": null,
"expires_at": null,
"updated_at": "2026-01-15T12:00:00+00:00"
}datais the entry's fields, shaped by the content type'sfields(see above); media and group references are expanded.seois its overrides. Both are maps,{}when empty.schemais ready-to-print JSON-LD when the content type names aschema_type.- A
delivertoken sees only published, unexpired entries. Apreviewtoken also sees drafts and in-review entries;statustells them apart.
Group sets
GET /groups — tag site. Account-wide group sets, plus those belonging to the website's own properties (property_slug says which; null means account-wide).
{
"id": "01000000-0000-4000-8000-000000000017",
"key": "towers",
"name": "Towers",
"object_type": "building",
"allows_multiple_membership": true,
"property_slug": null,
"groups": [{ "id": "0100…0018", "parent_id": null, "label": "North Tower", "slug": "north-tower", "description": null, "color": null, "sort_order": 1 }]
}A group's id is what the group filter accepts on /properties, /floor-plans and /units. Filtering by a parent includes its descendants.
Last updated on