Content endpoints
List and fetch published content (events, pages, posts, people, venues, and more) as JSON from your site
Most content types on your site expose a matching read-only JSON endpoint. They all share the same shape. A list endpoint returns a paginated array, and a detail endpoint returns one record by ID. Use them to add live content to a theme or an embedded widget without a redeploy.
Event instances and search have their own pages because they take extra parameters. Everything else follows the contract on this page.
Available endpoints
| Content type | List | Detail | Fields |
|---|---|---|---|
| Events | /api/events | /api/events/{id} | Event |
| Pages | /api/pages | /api/pages/{id} | Page |
| Posts | /api/posts | /api/posts/{id} | Post |
| Blogs | /api/blogs | /api/blogs/{id} | Blog |
| People | /api/people | /api/people/{id} | Person |
| Venues | /api/venues | /api/venues/{id} | Venue |
| Organizations | /api/organizations | /api/organizations/{id} | Organization |
| Seasons | /api/seasons | /api/seasons/{id} | Season |
| Series | /api/series | /api/series/{id} | Series |
| Works | /api/works | /api/works/{id} | Work |
| Smart collections | /api/smart-collections | /api/smart-collections/{id} | Smart collection |
Each endpoint accepts the .json suffix interchangeably with the bare path (/api/events.json and /api/events). Responses contain the same published content that renders on your site for visitors.
List a content type
GET {your-domain}/api/{type}.jsonCommon query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number to return. The maximum is 1000. Basker reduces a higher value to 1000. |
limit | integer | varies | Page size. The maximum is 500. Basker reduces a higher value to 500. Most types default to 10, pages default to 100, and events default to 500. |
sort | string | varies | Field to sort by. Prefix with - for descending (-publishDate). Defaults differ per content type. For example, posts sort by newest first, and people and venues sort alphabetically. |
Pages accept slug and relativePath. Posts accept slug, and blog=<blog slug> to list one blog's posts. Most other content lists accept slug. Event lists also accept depth (0 to 5) and select. For date, relationship, and custom attribute filters, see Filtering.
Every endpoint accepts locale. Without it, translated fields come back in the site's default language. Pass ?locale=cy (or another language the site offers) for another language.
Response
A standard paginated list contains a docs array plus pagination metadata. The depth parameter expands related records inline.
{
"docs": [
{
"id": "000000000000000000000005",
"title": "Remarkable Theatre News",
"slug": "remarkable-theatre-news",
"posts": {
"docs": [
{
"id": "000000000000000000000004",
"title": "How Moonclock was made",
"slug": "making-moonclock",
"url": "/posts/making-moonclock",
"publishDate": "2030-05-01T09:00:00.000Z",
"authors": []
}
],
"hasNextPage": false
}
}
],
"totalDocs": 1,
"limit": 10,
"totalPages": 1,
"page": 1,
"pagingCounter": 1,
"hasPrevPage": false,
"hasNextPage": false,
"prevPage": null,
"nextPage": null
}In /api/blogs.json and /api/blogs/{id}, each blog's posts is a paginated list of its published posts, newest first. It holds at most 10 posts. Add all=true to get every post, or use /api/posts.json?blog=<blog slug> to page through them. Each post there carries title, slug, url, publishDate, updatedAt, authors, image, description, and categories. Use url for links rather than building the path yourself.
Records that have saved template settings carry them at theme.settings, for example theme.settings.prefix on an item in /api/events.json. There is no top-level copy of those settings. The theme key is missing when a record has no saved template settings, so check it before you read from it.
List endpoints return a public summary chosen for that content type. Detail endpoints can return more fields. List endpoints return a public summary chosen for that content type. Detail endpoints can return more fields. Open the matching reference in the Fields column above for the template-facing model. Do not assume that every template field is present in a list response.
Rich-text fields come with a rendered-HTML companion alongside the plain value. For example, richTitle_html and richDescription_html accompany title and description. richName_html accompanies names on people. Use the _html value when you want ready-to-render markup. Use the plain value for link text and aria-label attributes.
Custom data relationships
Custom attributes and custom object fields can control how related records appear in public API responses. The setting is called Public API response in the editor.
| Setting | Response shape |
|---|---|
| Full record | Returns the expanded related record when depth expands that relationship. |
| Summary | Returns a compact object with identifying fields such as id, title, name, label, slug, or url. |
| Reference only | Returns only the related record ID, or an array of IDs for fields that allow multiple values. |
Use Summary or Reference only for relationships that reference large records. These need only a title, URL, or lookup ID in the browser.
Filtering
Five list endpoints accept filter parameters: /api/events, /api/event-instances, /api/posts, /api/organizations, and /api/smart-collections. The other list endpoints in the table above accept page, limit, sort, and their own slug lookup only.
Filters combine with AND. A request that sets a date range, a venue, and a category returns only the records that match all three.
Filtering happens at the edge
Basker caches a filtered list response the same way it caches an unfiltered one. Your site can send a narrow query straight from the browser, or from a server that renders your pages. The response still comes from the edge cache. See Caching.
Shortcut parameters
Each filterable endpoint accepts a short parameter for the relationships that themes query most.
| Endpoint | Parameter | Matches |
|---|---|---|
/api/events | venueId | The venue set on the event. |
/api/events | seasonId | The season set on the event. |
/api/events | seriesId | One of the series set on the event. |
/api/events | companyId | The company set on the event. |
/api/events | ids | A comma-separated list of event IDs. |
/api/event-instances | eventId | The parent event. |
/api/event-instances | venueId | The venue set on the instance. |
/api/event-instances | seriesId | One of the series set on the instance. |
/api/event-instances | seasonId | The season set on the parent event. |
/api/posts | blogId, authorId, categoryId, tagId | One related record each. |
/api/posts | authorIds, categoryIds | Comma-separated lists. A post matches when it has any one of the values. |
/api/organizations | type | The organization type. |
/api/events.json?venueId=000000000000000000000003
/api/event-instances.json?venueId=000000000000000000000003&limit=50Field filters
For any other field, use a where parameter. The pattern is where[field][operator]=value.
| Operator | Matches |
|---|---|
equals, not_equals | An exact value, or anything other than it. |
in, not_in | Any value in a comma-separated list. |
greater_than, greater_than_equal | Values above a number or a date. |
less_than, less_than_equal | Values below a number or a date. |
like, contains | Text that includes the value. |
exists | Records where the field is set (true) or empty (false). |
Dates take an ISO 8601 timestamp. This is the query behind a month view in a calendar:
/api/event-instances.json
?where[startDate][greater_than_equal]=2026-10-01T00:00:00.000Z
&where[startDate][less_than]=2026-11-01T00:00:00.000ZGroup conditions with and and or when one field is not enough:
/api/events.json?where[or][0][title][like]=mozart&where[or][1][description][like]=mozartCustom attribute filters
Filter on a custom attribute with attributeWhere[custom.{key}][{operator}]=value. The custom. prefix is optional. Use attributeWhere[{key}] when the attribute belongs to a collection block.
/api/events.json?attributeWhere[custom.category][in]=bookbug,family-funattr[{key}]=value is a shorthand for an equals match on the same attribute:
/api/events.json?attr[category]=bookbugAttributes that hold text, numbers, dates, checkboxes, and select values accept equals, not_equals, in, contains, like, exists, greater_than, greater_than_equal, less_than, and less_than_equal. Attributes that link to another record accept equals, in, and contains only.
Pass in values as one comma-separated list. Basker matches values exactly, so send the stored value rather than the editor label.
What a filter cannot reach
Filters narrow the public list. They never widen it. Every list response stays inside these limits, whatever the query asks for.
- The list returns published records only. Drafts and scheduled records stay out until they publish.
/api/event-instancesexcludes instances that editors have hidden./api/event-instancesexcludes instances before the start of today unless the request setsshowPast=true./api/eventsreturns only events that have not finished. It has noshowPastparameter. To read past dates, query/api/event-instanceswithshowPast=true.
A date filter does not override showPast
A request to /api/event-instances for a range in the past returns an empty list unless it also sets showPast=true. The two conditions combine with AND.
Worked example
This request asks a "what is on" page for one venue, one month, and two categories:
const params = new URLSearchParams({
'where[startDate][greater_than_equal]': '2026-10-01T00:00:00.000Z',
'where[startDate][less_than]': '2026-11-01T00:00:00.000Z',
venueId: '000000000000000000000003',
'attributeWhere[custom.category][in]': 'bookbug,family-fun',
select: 'startDate,event.title,event.url,venue.title',
limit: '200',
});
const res = await fetch(`/api/event-instances.json?${params}`);
const { docs } = await res.json();Get one record by ID
GET {your-domain}/api/{type}/{id}Returns the record wrapped in a doc key: { "doc": { ... } }. A detail response can contain more fields than its list summary. The id comes from a list response or from a relationship field on another record.
Errors
| Status | Meaning |
|---|---|
400 | The id is missing or not a valid identifier. |
404 | No record with that ID exists, or your site does not have access to it. |
500 | Server error. |
Field selection
/api/events and /api/event-instances accept ?select= with a comma-separated list of dotted field paths. The response always includes the full pagination wrapper. The select parameter narrows only the items inside docs.
/api/events.json?select=title,slug,image.urlUse field selection to keep payloads small when a grid or list only needs a few fields per record.
Examples
Fetch the latest posts for a feed:
const res = await fetch('/api/posts.json?limit=6');
const { docs } = await res.json();Look up a single venue by ID:
const res = await fetch(`/api/venues/${venueId}`);
if (res.ok) {
const { doc: venue } = await res.json();
}Caching
When edge caching is enabled for your site, list responses can be served from the edge and refresh when an editor publishes a change. Public responses carry Cache-Control: public, s-maxage=3600, max-age=60, stale-while-revalidate=86400, stale-if-error=86400.
Keep query parameters stable across visitors so responses stay cacheable. A filtered URL caches as well as an unfiltered one. Build the same query for every visitor who sees the same view. Avoid cache-busters and per-visitor timestamps unless you need a fresh response.
Two cases change the header. A password-protected site returns a private response that only the browser caches. A preview request is never cached.
See also
- Event instances: performances, with date filtering and ticketing data.
- Search: full-text query across every content type at once.
- Custom objects: read your site custom data.