Files
typo3-13/docs/cms-api.md
T
frommeandClaude Opus 5.5 2bd663a9bf docs: CMS API and calendars
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]>
2026-10-29 15:37:36 +01:00

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.
  • 400 without hotel, 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. 400 without it, 404 {"message": "Product not found"} for an unknown code.
  • hotel (optional): adds hotel with 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) or null.
[
  {"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. type is one of product, hotel, region, country, city, concept, news; uids comma-separated. Uids that are no longer eligible are left out, not answered with an error (the consumer reads them as deleted).
  • 400 for an unknown type, no uids or more than 100 uids; 404 for other paths.
  • 503 with Retry-After: 3600 when the feed is switched off (contentFeedEnabled = 0, the kill switch for when the host is struggling), 503 when contentFeedSites is 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.