Concepts for developers
Spatibase stores map content as types made of elements (fields), filled in as entries, and serves only the published copy through a read-only Content Delivery API. This page explains each piece for developers, using one example throughout: a map of coffee shops.
How does the Spatibase model fit together?
A project holds reusable elements, types built from those elements, entries of those types, and hand-picked groups of entries. Only the published copy of each entry reaches your app.
Project "Prague Coffee" one UUID, one API address
|
|-- Elements (reusable fields) description, photos, rating, opens-at ...
|
|-- Types (what an entry is) an ordered list of elements + map settings
| Venue locationMode: required, color #e11d48
| |-- Cafe (subtype) inherits all Venue elements, adds its own
| `-- Roastery (subtype)
|
|-- Entries (the content itself) "Bean There" (Cafe) + values + main location
| draft copy --ready + publish--> published copy <- only this reaches the Content Delivery API
|
`-- Groups (hand-picked, ordered lists) "Featured on homepage"
What is a project?
A project is the container for all content of one map or site, identified by a UUID that appears in every API URL. Find it in the web app’s address bar (https://app.spatibase.com/projects/<id>/entries) or on the project’s API page, which also shows ready-made URLs for that project.
https://api.spatibase.com/delivery/v1/projects/$PROJECT_ID
$PROJECT_ID is the UUID in the project’s address. A project’s Content Delivery API is public by default; the owner can make it private so that every request needs an API key (Authentication).
What are elements and element kinds?
An element is a reusable field, defined once per project and assigned to any number of types. Each element has a label, a stable apiKey (the key in API responses, for example rating) and a kind that decides what it holds and how you can filter it.
| Kind | Holds | Value in the API |
|---|---|---|
text, markdown, identifier |
text, rich text, a unique slug | string (text with the JSON editor: the parsed JSON) |
number, boolean, color |
a number, yes or no, #rrggbb |
number, boolean, string |
date |
a date, date-time or time, or a range | string, or {start, end} for ranges |
choice |
one or several options (option trees up to 4 levels) | string or array of strings |
link, contact, location, embed |
structured values | objects |
phone |
a phone number as typed | string |
images, files |
uploaded assets | array of asset objects |
reference |
another entry, or several | {id, type, title}, or the full entry with include=references |
geo |
extra shapes (points, lines, areas) | GeoJSON FeatureCollection |
Values are always keyed by apiKey. When someone renames an apiKey in the web app, Spatibase rewrites the stored values to the new key, so update your code at the same time. The exact JSON shape of every kind is in Field values.
What are types and subtypes?
A type, such as “Cafe”, is an ordered list of assigned elements plus map settings. Every entry belongs to exactly one type.
locationMode:required(marking ready needs a main location),optional, ornone(pure content such as articles; these entries never appear on the map, in GeoJSON or in vector tiles).geometryKinds: which shapes the main location may be:Point,LineString,Polygon.color: the type’s color (Type color in the app), carried into vector tiles as thecolorproperty.
Types form a tree up to 5 levels deep. A subtype inherits every element of its ancestors and can add its own. Asking for a parent type returns its subtypes too: type=venue also returns cafes and roasteries. Every entry still reports its own type and a typePath such as ["venue", "cafe"].
Switching a type off in the content model hides the type, its subtypes and all their entries from the Content Delivery API until it is switched on again. Working with subtypes in code is shown in Recipes.
What is an entry and its main location?
An entry is one record of a type: a title, fields keyed by element apiKey, and an optional main location. The main location (geometry) is a GeoJSON Point, LineString or Polygon in WGS84, with coordinates in [lng, lat] order.
The main location drives the map: it is what bbox, near and sort=distance search, what entries.geojson returns as the feature geometry, and what vector tiles draw. Extra shapes, such as a delivery area or a parking lot, live in geo elements and never affect spatial filters.
{
"id": "9dc8c38c-5d1e-4a51-9c3b-1f0e2a7d6b10",
"type": "cafe",
"typePath": ["venue", "cafe"],
"title": "Bean There",
"geometry": { "type": "Point", "coordinates": [14.4208, 50.0875] },
"fields": { "description": "Small **coffee** bar.", "rating": 4.7 },
"groups": ["featured"],
"createdAt": "2026-10-01T09:12:44.000Z",
"updatedAt": "2026-10-02T14:03:10.000Z",
"publishedAt": "2026-10-02T14:03:10.000Z"
}
What is a group?
A group is a named, manually ordered list of entries of any type, for example “Featured on homepage” or one list per website. Editors set the order by hand. Read a group with /groups/<groupKey>, or combine it with filters through /entries?group=<groupKey>&sort=group.
Group changes go live with the next publish, like entries: the Content Delivery API shows the group as it was at the last publish. A group only ever lists published entries of enabled types, so an unpublished member simply does not appear.
What are map feature types?
Map feature types are named, styled categories of map shape, such as “Path”, “Trailhead” or “Park area”, each with a geometry kind, an icon and a color. A geo element can restrict its shapes to some of them; each shape then carries properties.featureType with the feature type’s apiKey.
List them at /feature-types:
{"apiKey":"path","name":"Path","geometryKind":"LineString","icon":"route","color":"#b45309"}
Lengths and areas shown in the web app’s map popups are not part of the API response.
How do draft and published copies work?
Editors always work on a draft. An editor marks a draft ready, and a project-wide publish copies every ready draft into a separate published copy, after checking required fields, together with staged unpublishes and removals and group changes. One publish is one numbered version of everything live, and any kept version can be restored (see Versions and going back). Unpublishing removes the published copy at the next publish. The Content Delivery API reads only the published copy, so saving a draft never changes what your app sees.
| Entry status | Meaning | In the Content Delivery API |
|---|---|---|
draft |
never published, or unpublished | not returned; 404 by id |
published |
published, no edits since | returned |
changed |
published, with newer unpublished edits | the last published version |
Your app never needs to filter drafts out, and cannot see them even by mistake. The editor’s side of this is described in Draft and published.
How do content version and caching work?
Each project has a contentVersion integer that increases whenever Content Delivery API output can change: a publish that ships something (which covers unpublishing, deleting a published entry and group changes), going back to an earlier version, an asset change or a content model change. The version numbers of the Versions page are different: they count publishes only. Saving a draft does not change it.
Every Content Delivery API response carries an ETag that includes the content version, and public projects send:
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=86400
Send the ETag back in If-None-Match to get a bodiless 304 Not Modified. Browsers and CDNs can therefore cache aggressively and still pick up a publish within about a minute in browsers and five minutes on a CDN. Details are in Content Delivery API: caching, with a client example in Recipes.
Which API should I use: Delivery or Management?
Use the Content Delivery API for websites, apps and maps that show published content. Use the Content Management API only when you need to change content from a script, because it works on drafts and the content model and needs a signed-in session.
| Content Delivery API | Content Management API | |
|---|---|---|
| Base URL | https://api.spatibase.com/delivery/v1/projects/$PROJECT_ID |
https://api.spatibase.com/api/projects/$PROJECT_ID |
| For | your websites, apps and maps | the Spatibase web app and scripts that edit content |
| Methods | GET only, CORS open to any origin |
read and write |
| Access | public, or an API key for private projects | a signed-in session (emailed sign-in link or code) |
| Content | published only | drafts and published |
| Caching | ETag and 304, CDN-friendly |
none |
| Versioning | versioned (v1) |
not versioned; it follows the web app and can change |
| Machine-readable spec | OpenAPI 3.1 files: one typed for your project, one generic | none |
Asset files (images and other uploads) are served from https://api.spatibase.com/assets/<assetId>/<filename> and stay reachable by their URL even in private projects (Assets and images). AI assistants use a third entry point, the MCP server (MCP server).
Related
Updated