Part of the Content API. Endpoints for the site’s pages: content pages, agent landing pages, market report pages, area pages, the home page, page templates and revisions.
Content pages
/api/v3/content/pages//api/v3/content/pages/<id>/Regular content pages. Scopes: pages:read / pages:write. Agent landing pages and market report pages have their own endpoints; coming soon pages and valuation pages are managed in the admin and are not visible here.
| Field | Type | Notes |
|---|---|---|
id, path, url, level, children_count |
Read-only. | |
slug |
string | Required; letters, numbers, -, _, /. |
parent |
int / null | Id of the parent page; read as {"id", "slug", "path"}. |
anchor_text |
string ≤256 | Required; the page name used in navigation. |
title, meta_description, meta_keywords |
string | SEO fields. |
content |
HTML | Sanitized. |
template |
string | One of GET /api/v3/content/templates/; default Page with Search. |
listing_header |
string | Header above the property listings. |
number_of_properties |
int | One of 0, 3, 5, 6, 10, 12, 15, 20, 24, 25, 30, 40, 50, 60, 75, 100, 120; default 12. |
property_display_location |
above / below |
Listings above or below the content; default below. |
search_header |
string | Header above the search form. |
search_form_type |
default / typeahead |
Which search form the page shows. |
search_field_defaults |
same as search |
Saved search whose criteria pre-fill the search form; null to clear. |
sidebar |
int / null | Id of a sidebar; read as {"id", "name"}. |
search |
see below | The saved search whose listings the page shows; null to detach. |
extra_content |
object | Template-specific areas, see below. |
footer |
int / null | Id of a footer; read as {"id", "name", "default"}. |
banner |
int / null | Id of a banner to show across the top of the page; read as {"id", "name"}. |
landscape_image_override |
see below | The big image/video at the top of the page. |
landscape_image_override_alt_text |
string ≤100 | |
landscape_image_override_content_type |
MIME | Derived from the URL’s extension when omitted. |
banner_id |
int / null | Read-only; the same id as banner, kept for older clients. |
capture_form_id, require_capture |
Read-only; managed in the admin. |
landscape_image_override is null to use the site’s header image, "none" to hide the landscape section, or a file URL (image or .mp4 video; see Files). Area pages and the home page take the same fields.
The search field
search reads as {"id", "short_id", "description", "criteria", "site_criteria"} where criteria is {field: [values]}. To set it, send a saved search’s short_id (the base36 id in the site’s search URLs), its numeric id, or a criteria object such as {"city": ["Riverside"], "list_price_min": 1000000}. A criteria object is validated against the site’s search field catalog, unknown fields are rejected with a 422 naming them, and the resulting search is saved (or reused if identical). Area pages and the home page take the same sidebar, search and footer values.
site_criteria holds what the site’s own settings add to every search, such as the MLS boards a site is limited to. You don’t need to send it: the site applies it again on save. Sending criteria back, with or without site_criteria merged in, is accepted and gives the same search.
Location values (city, county, zip, subdivision and the site’s other location fields) are matched exactly when listings are searched, so "McLean" would find nothing on an MLS that spells it "Mclean". Criteria objects are therefore checked against the values the site’s search knows: a value that matches one known value apart from capitalization is saved in the MLS spelling, and the response’s criteria shows what was stored. A value that matches no known value, or several that differ only in capitalization, is saved as sent, and the write succeeds with a warning (unknown_value or ambiguous_value) naming up to three close matches:
{"id": 12, "warnings": [{ "code": "unknown_value", "field": "search", "criterion": "city", "value": "Riversid", "suggestions": ["Riverside"], "message": "city \"Riversid\" is not a known value for this site, so the search may find no listings"}]}
Other fields, such as prices, are not checked.
To discover the fields and values a site accepts, and to test criteria before attaching them, see Property Searches.
Template areas (extra_content)
Some templates add fields, listed per template by GET /content/templates/. They read and write as an object keyed by the area name with spaces as underscores; on write, keys are merged into what is stored (send null to clear one), unknown keys are a 422, and changing template drops areas the new template lacks. Values by area type: text is a string, rich_text is sanitized HTML, file is a file URL, reorder_agents is a list of Agent Detail page ids.
- Agent Detail Page:
Agent_Name,Agent_Photo(file URL),Cell_Phone_Number,Fax_Number,Email,Company,Address,Testimonials(HTML). Create one with"template": "Agent Detail Page". - About Page:
Testimonials(HTML) andAgent_Ordering(ids). An About page also carries a read-onlyagentslist, the site’s Agent Detail pages in display order as{"id", "name", "path", "url", "photo_url"}; pages not inAgent_Orderingfollow the ordered ones.
Validation, filters and limits
Validation mirrors the admin: the resulting URL must be unique across all pages, must not be a path Real Geeks reserves (search, market reports, the blog root, …), and a parent change must not create a loop.
List filters: slug, path (e.g. ?path=/resources/buyers/), parent (id or null), template, q (anchor text / title / slug contains), ordering (slug, level, id). List results leave out content, extra_content and agents; fetch a single page for those.
Pages nest at most 10 levels deep and a page URL is at most 200 characters. Deleting a page with children returns 409 conflict; pass ?orphan_children=true to delete it and make the children top-level pages.
From the command line: geekcli pages list, geekcli pages get /about/, geekcli pages update /about/ --content-file about.md with geekcli (see the geekcli guide).
Agent landing pages
/api/v3/content/agent-pages//api/v3/content/agent-pages/<id>/Content pages tied to a CRM agent: leads from the page go to that agent instead of the site’s round robin. Same fields and rules as content pages plus agent_id (writable; an id from GET /content/agents/, or null) and read-only agent_name. These pages are separate from /content/pages/ (neither lists the other). Scopes: pages:*.
GET /content/agents/ returns the site’s CRM agents as {"results": [{"id", "name"}]}; 502 crm_unavailable if the CRM cannot be reached, and writing agent_id is refused with the same code until it can be checked.
From the command line: geekcli agents, geekcli agent-pages create --agent-id <id> with geekcli (see the geekcli guide).
Market report pages
/api/v3/content/market-report-pages//api/v3/content/market-report-pages/<id>/A market report page shows market statistics and tables of active, pending and sold listings for one saved search. These pages are separate from /content/pages/ (neither lists the other), the template is fixed, and the fields are the ones the admin offers. Scopes: pages:*.
| Field | Type | Notes |
|---|---|---|
slug, parent, anchor_text, title, meta_description, meta_keywords |
As on content pages; slug and anchor_text are required. |
|
search |
see The search field | Required: the area the report covers. It cannot be null. |
header |
string ≤127 | Optional text at the top of the report, above the sign-up call to action. |
content |
HTML | Sanitized. |
sold_within |
int | Months of sold listings in the Sold table: one of 1, 2, 3, 4, 5, 6, 12, 18. Default 6. |
number_of_properties |
int | Rows in each listings table, 1 to 50. Default 6. |
search_field_defaults |
same as search |
Pre-fills the search form; null to clear. |
footer |
int / null | As on content pages. |
{"slug": "riverside-market", "anchor_text": "Riverside Market Report", "search": {"city": ["Riverside"]}, "sold_within": 12}
There is no template, sidebar, banner, extra_content or landscape override on a market report. List filters, ordering, pagination, PUT, DELETE with ?orphan_children=true and revisions work as on content pages. Pages are live as soon as they are created.
Area pages
/api/v3/content/area-pages//api/v3/content/area-pages/<id>/Same shape as content pages without template/extra_content, plus area_name (required) and featured (bool). Extra filter: featured=true|false. Scopes: area_pages:*.
An area page’s listings come only from its search; area_name does not filter them. A write that leaves an area page without a search succeeds with a no_search warning (the page shows no listings), and one whose search has nothing beyond the site’s built-in limits (such as the MLS boards a site is limited to) succeeds with a no_filter warning (the page shows every listing on the site). Either can be deliberate, such as an “all homes for sale” page. A limit field counts as a filter when it picks some of the values the site allows, such as one city on a site limited to several. On update the check applies only when search is sent (always on PUT, which replaces the page).
search_header, the heading above the search form, defaults to anchor_text on create when it is not sent; send null or "" for the site’s generic search title.
From the command line: geekcli area-pages list, geekcli area-pages update /riverside/ with geekcli (see the geekcli guide).
Home page
/api/v3/content/home-page/The site’s single home page. Scopes: home_page:*. Writable: title, meta_description, meta_keywords, content, sidebar, footer, banner, tile_group (a Featured Pages group id or null, anna-modern), the landscape override fields, the property display options search, listing_header, number_of_properties, property_display_location, property_display_type (carousel, grid or null), and the search form options search_header, search_subheader, search_form_type, search_form_tabs (bool), search_field_defaults, search_image (file URL or null), and featured_agents (see Featured agents).
Some of these only render on some designs (for example property_display_type and search_form_tabs on anna-modern), matching the admin. A site without a home page returns 404 home_page_missing; create it in the admin.
Featured agents
featured_agents is the list of agents shown on the home page as cards with a photo and bio. It is a list of Agent Detail page ids: content pages with "template": "Agent Detail Page", listed by GET /content/pages/?template=Agent Detail Page. They are page ids, not the CRM agent ids from GET /content/agents/.
Send the full list to replace it, and [] (or null) to remove every card. Ids that are not Agent Detail pages, duplicates and non-integers are a 422. The list picks which agents are featured, not their order. The cards render on the anna-modern home page, and on anna in page sidebars when the site has featured agents in the sidebar enabled; other designs ignore the field.
{"featured_agents": [42, 57]}
Each card is built from the Agent Detail page itself; there is nothing to edit on the home page beyond the list. To change what a card shows, PATCH /content/pages/<id>/ on that page:
| On the card | Comes from |
|---|---|
| Name (heading) | The page’s title (not anchor_text or extra_content.Agent_Name). |
| Bio text | The page’s content, with HTML tags stripped, shown in full. |
| Photo | extra_content.Agent_Photo, a file URL (upload it with Files first). With none set the card has no photo. |
| “Learn More” link | The page’s slug (/<slug>). |
The same page is the agent’s profile page and appears on the About page, so one edit updates all three.
From the command line: geekcli home-page get, geekcli home-page update with geekcli (see the geekcli guide).
Page templates
/api/v3/content/templates/The page templates this site can use, with their extra content areas. Accepts any valid key.
{"results": [ {"name": "About Page", "description": "...", "extra_content_areas": [ {"name": "Testimonials", "type": "rich_text"}]}]}
From the command line: geekcli templates list with geekcli (see the geekcli guide).
Revisions and undo
.../revisions/.../revisions/<rev>/.../revisions/<rev>/revert/Almost everything the API can change can be undone. Each of these keeps a revision history at its own revisions/ path:
| Resource | Revisions at |
|---|---|
| Content pages | /content/pages/<id>/revisions/ |
| Agent landing pages | /content/agent-pages/<id>/revisions/ |
| Market report pages | /content/market-report-pages/<id>/revisions/ |
| Area pages | /content/area-pages/<id>/revisions/ |
| Home page | /content/home-page/revisions/ |
| Blog posts | /blog/posts/<id>/revisions/ |
| Footers | /content/footers/<id>/revisions/ |
| Sidebars | /content/sidebars/<id>/revisions/ |
| Navigation bars | /content/navigation-bars/<id>/revisions/ |
| Featured pages | /content/featured-pages/<id>/revisions/ |
| Banners | /content/banners/<id>/revisions/ |
| Site settings | /settings/revisions/ |
| Design | /design/revisions/ |
A revision covers every field you can write on the resource. On pages that includes slug, parent, title, the meta_* fields, banner, the landscape image and, on agent landing pages, agent_id; on blog posts it includes categories and the comment switches. A sidebar’s revision covers its name and its whole list of items, a navigation bar’s its whole list of links, and a featured pages group’s its title, blurb and tiles, each list with its order.
For content this is the same history as the Versions page in the site admin, so changes made in the admin appear here and can be reverted here, and the other way round. One request is one revision, however much it changes: a PATCH of a sidebar’s name and items, or a PUT of a navigation bar’s links, is undone in one step. Revisions are attributed to the API key that made them.
GET .../revisions/lists revisions newest first:{"id", "at", "by", "action": "created|changed|reverted", "changed_fields", "revertible"}, wherebynames the person the key belongs to and the key used. Admin edits haveapi_key: null.GET .../revisions/<rev>/addspreview: per changed field, the value now and the value a revert would restore. Lists (items,links,tiles) are shown the way the resource shows them, andcategoriesas ids.POST .../revisions/<rev>/revert/(write scope) undoes that revision and every later one, returning the resource. The revert is itself a revision, so it can be undone the same way. The creation revision cannot be reverted; delete the object instead.
When a revert is refused. A revert answers 409 conflict and changes nothing when the earlier state can no longer be restored: another page now has that URL, the earlier parent has since been moved under the page, another sidebar, banner or featured pages group has taken the name, or (design) the earlier template is no longer offered.
List entries that a revert brings back, such as a deleted sidebar item, navigation link or tile, are new entries with new ids. Entries that still exist keep theirs.
Settings and design. Their revisions come from the site’s settings history. They list only changes to the settings this API exposes, whoever made them: by.api_key is set for changes made through the API, and by.name is the person or tool recorded for the others. The list goes back over the site’s 500 most recent settings saves. Design revisions have changed_fields of template and styles. In a settings preview null means the site had no value of its own, so reverting returns it to the inherited default. A revert is validated like any other settings or design change.
What cannot be undone. Deleting an object: its revisions go with it. Blog categories and the blog home page are recorded in the site’s change log only. Files have their own undo, for 90 days: see Restoring files.
From the command line: geekcli pages revisions /buying/, geekcli posts revision <slug> <rev>, geekcli footers revert 1 <rev> with geekcli (see the geekcli guide). The same three subcommands work on pages, agent pages, area pages, posts, footers and the home page.
