docs/cms-api.md describes the endpoints TYPO3 serves to MyE&P and the chatbot (/api/hotel, /api/product, /api/calendar-hotels, /api/content/*): key, parameters, responses, errors. It is the other side of MyE&P's API consumer guide. docs/calendars.md covers the price calendar, the Belegungskalender and the iCal feed: which product gets which, the MyE&P endpoints behind them, caching, troubleshooting, and the rule that a product's calendar hotel must carry the BusPro code, not a group house's CMS code (which broke three example trips). The README replaces the TYPO3 base distribution boilerplate and links both. The plugin renaming SQL in ep_products' README is obsolete since the migration. The cmsApiKey description names /api/calendar-hotels. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.4 KiB
CMS API
Endpoints TYPO3 serves to other systems: MyE&P (hotel and product content, calendar hotels)
and the chatbot (content feed). They are answered by EP\EpProducts\Middleware\ApiMiddleware
before the page resolver, so they do not depend on a page and are never page-cached.
The other side of these contracts is documented in MyE&P's docs/api-consumer-guide.md
(EP/myep).
Authentication
All endpoints need the shared key cmsApiKey from the ep_products extension configuration
(Settings → Extension Configuration → ep_products, tab ContentFeed):
- header
X-Api-Key: <key>(preferred, query strings end up in access logs), or - query parameter
?key=<key>.
A missing or wrong key answers 403 {"message": "Invalid or missing api key"}. An empty
cmsApiKey denies every request. MyE&P sends the key as APP_CMS_API_KEY; both sides must be
changed together.
GET /api/hotel?hotel=<code>
Content of one hotel, for MyE&P's group house pages and booking flow.
hotel: the TYPO3 hotel code or one of its matchcode aliases. In MyE&P this is the accommodation's CMS code (e.g.DGSGRP), which can differ from its calendar code.400withouthotel,404 {"message": "Hotel not found"}for an unknown code.
{
"name": "…", "code": "…",
"description": "…", "features": "…", "room_types": "…",
"additional_information": "…", "address": "…",
"images": {"original": [{"url": "…", "alt": "…", "title": "…"}], "resized": […]},
"icons": […],
"region": {"name": "…", "latitude": …, "longitude": …, "webcam": "…", "ski_area": "…",
"ski_area_extended": "…", "description": "…", "news": "…", "length": …,
"altitude": …, "lifts": …, "images": {…}, "region_maps": [{"url": "…", "alt": "…", "title": "…"}]}
}
GET /api/product?product=<code>[&hotel=<code>]
Content of one product, optionally with a hotel.
product: the product code.400without it,404 {"message": "Product not found"}for an unknown code.hotel(optional): addshotelwith the same content as/api/hotel.
{
"product": {"name": "…", "code": "…", "images": {…}},
"country": {"name": "…"},
"region": {…},
"city": {"name": "…"},
"hotel": {…}
}
GET /api/calendar-hotels
The calendar hotel of every visible product: the hotel codes whose availability TYPO3 shows (iCal feed, availability calendar, price calendar). MyE&P syncs its contingent snapshot for these codes in addition to its accommodations, so hotels offered only in winter, which have no accommodation in MyE&P, have availability too. See calendars.md.
- Only products and hotels that are not hidden or deleted; hotels without a code are left out.
- Sorted by code; products by uid. Names have line breaks collapsed.
season:"s"(summer),"w"(winter) ornull.
[
{"code": "DKI", "name": "Sportclub Schwendi", "products": [
{"uid": 155, "name": "Sportclub Schwendi", "season": "w"},
{"uid": 362, "name": "Gruppenhaus Schwendi", "season": "s"}
]}
]
Every code in this list should be a BusPro calendar code. A group house's content record
(…GRP, …SO) set as a product's calendar hotel puts its CMS code in here, which bpn-connect does
not know (see calendars.md).
GET /api/content/manifest and GET /api/content/records?type=<type>&uids=<uids>
The content feed for the chatbot (EP\EpProducts\ContentFeed\ContentFeedApi).
manifest: everything the feed publishes (pages of the configured sites and records), with a modification timestamp per item. Cached for 10 minutes.records: up to 100 records of one type per request.typeis one ofproduct,hotel,region,country,city,concept,news;uidscomma-separated. Uids that are no longer eligible are left out, not answered with an error (the consumer reads them as deleted).400for an unknown type, no uids or more than 100 uids;404for other paths.503withRetry-After: 3600when the feed is switched off (contentFeedEnabled = 0, the kill switch for when the host is struggling),503whencontentFeedSitesis empty. The consumer keeps what it has on a 503; nothing is deleted on the chatbot side.
Configuration (extension configuration ep_products, tab ContentFeed): contentFeedEnabled,
contentFeedSites, contentFeedLanguages, contentFeedExcludedPages,
contentFeedNewsDetailPages.