CMStart API v0.5.17

Multi-channel hotel distribution platform. Manage properties, sync availability, and control pricing across booking channels from a single API.

What CMStart Does

⛪

Hotel Management

Create, update, and manage hotel properties with subscription tracking and admin settings.

⇄

Channel Sync

Distribute rates and availability across multiple booking channels from a single source of truth.

🔒

Two-Tier Auth

Separate Consumer and Admin keys, plus per-hotel credentials on every PMS endpoint. A leaked PMS key alone cannot reach any hotel without its user/parola.

📋

Reservations

Search and manage reservations across all channels with filtering by date, status, and guest details.

📈

PMS Integration

Connect to property management systems with room, rate, and child category mapping and reporting.

🔍

Logs & Monitoring

Debug logs, slow query tracking, channel update history, and PMS request inspection in one place.

⭐

Booking Reviews

Proxy guest reviews and post property replies via Booking.com’s review API with automatic JWT refresh.

📊

Booking Scores

Fetch property score summaries and category breakdowns from Booking.com’s property-scores API.

AI Integration Guide

Copy the snippet below and paste it into your AI agent's system prompt or tool configuration.

# CMStart API — AI Integration Guide

## Base URL

https://cmstartapi01.azurewebsites.net

## Authentication

Two API keys, scoped by tier. Each tier-tagged endpoint requires its matching key in the `X-Api-Key` header.

    X-Api-Key: <consumer-or-admin-key>

**Consumer key** unlocks `POST /api/hotels/add`, `GET /api/channels`, the `/api/hotelchannels/*` routes, and every `/api/pms/*` route. Every `/api/pms/*` request must additionally carry per-hotel credentials:

    X-Hotel-Id:       110
    X-Hotel-User:     hotel_username
    X-Hotel-Password: hotel_plaintext_password

The triple is validated server-side against the hotel’s stored credentials. If the route URL includes a `{hotelId}` segment it must equal `X-Hotel-Id`.

**Admin key** unlocks everything else under `/api/*` — hotels list/get/edit/extend, settings, logs, reservations, bookingreviews, bookingscores.

Open paths (no key required): `/health`, `/version`.

Wrong tier, missing key, or invalid hotel credentials → `401 Unauthorized`.

## Endpoints

### Hotels

    GET    /api/hotels/                          # [Admin]    List hotels (?showExpired=true)
    GET    /api/hotels/{hotelId}                  # [Admin]    Get hotel details
    POST   /api/hotels/add                        # [Consumer] Create a hotel (no hotel-creds required)
    PUT    /api/hotels/{hotelId}                  # [Admin]    Update a hotel
    PATCH  /api/hotels/{hotelId}/extend           # [Admin]    Extend subscription

### Channels — [Consumer]

    GET    /api/channels/                         # List all channels

### Hotel Channels — [Consumer]

    GET    /api/hotelchannels/                    # List hotel-channel connections
    GET    /api/hotelchannels/{id}                # Get connection details
    POST   /api/hotelchannels/add                 # Create a connection
    PUT    /api/hotelchannels/{id}                # Update a connection
    PATCH  /api/hotelchannels/{id}/toggle         # Toggle autorizat | sincronizat_camere | ignora_pms_preturi

Read responses include per-binding currency fields: `monedaCanal`, `cursSchimb`,
`rotunjire`, `ignoraPmsPreturi`. `ignora_pms_preturi` freezes outbound prices when set.

### Settings — [Admin]

    GET    /api/settings/{camp}                   # Get a setting by key

### Logs — [Admin]

    GET    /api/logs/debug                        # List debug logs
    DELETE /api/logs/debug                        # Clear debug logs
    GET    /api/logs/slow-queries                 # List slow queries
    DELETE /api/logs/slow-queries                 # Clear slow queries
    GET    /api/logs/actions                      # List action logs
    GET    /api/logs/channel-updates              # List channel update logs
    GET    /api/logs/pms-requests                 # List PMS request logs
    GET    /api/logs/pms-requests/room-mappings   # Get room mappings
    GET    /api/logs/pms-requests/{logId}         # Get PMS request detail

### Reservations — [Admin]

    GET    /api/reservations/                     # Search reservations

### PMS — all routes are [Consumer] and require hotel-creds headers

    GET    /api/pms/reports                       # PMS reports
    GET    /api/pms/connections                   # List PMS connections
    POST   /api/pms/connections/setup             # Set up a new connection
    POST   /api/pms/connections/{id}/authorize    # Authorize a connection
    GET    /api/pms/connections/{id}/channel-rooms # Live channel rooms + rate plans (mapped/unmapped), no writes
    GET    /api/pms/connections/{id}/rooms         # List room mappings
    POST   /api/pms/connections/{id}/rooms         # Save room mappings
    GET    /api/pms/connections/{id}/rates         # List rate mappings
    POST   /api/pms/connections/{id}/rates         # Save rate mappings
    GET    /api/pms/connections/{id}/childcategories  # List child categories
    POST   /api/pms/connections/{id}/childcategories  # Save child categories
    POST   /api/pms/init                          # Seed PMS catalog (rooms, rate plans, child categories) for a hotel
    POST   /api/pms/prices                        # Push daily prices (+ valoriCopii/valoriPS optional)
    GET    /api/pms/prices?hotelId=&from=&to=&canalId=  # Read prices: hotel-level, or per-channel post-conversion when canalId set
    POST   /api/pms/restrictions                  # Push per-channel restrictions (closed, min/max stay, etc.)
    GET    /api/pms/restrictions?hotelId=&canalId=&from=&to=  # Pending (un-pushed) restrictions
    POST   /api/pms/availability                  # Push availability counts (global or per-channel)
    GET    /api/pms/availability?hotelId=&canalId=&from=&to=  # Read current availability

`POST /api/pms/init` is the JSON port of legacy `pms/ms/init.php`. Body shape:

    {
      "hotelId": 110,
      "vanzarePerCamera": false,
      "rooms": [
        { "pmsId": "DBL", "name": "Dubla", "maxCamere": 5, "maxOcupare": 2,
          "rates": [ { "pmsId": "BB", "name": "Bed and breakfast" } ] }
      ],
      "categoriiCopii": []
    }

Wraps every write in one MySQL transaction. Upserts `camere`, `camere_variante_pret`, and
`categorii_copii` keyed on `(hotel_id, pms_id)`. Cascade-deletes channel mappings for
removed cameras. Cameras / rate plans referenced by `rezervari` are renamed to
`[DELETED] {original} #{id}` instead of hard-deleted, so reservation history is preserved.

### PMS Tariff Optimizer — [Consumer], hotel-creds required, route `{hotelId}` must equal `X-Hotel-Id`

    GET    /api/pms/optimizator/{hotelId}         # Read tariff-optimizer config (defaults if unset)
    PUT    /api/pms/optimizator/{hotelId}         # Save tipOcupare, rotunjire, reguli[]
    POST   /api/pms/optimizator/{hotelId}/toggle  # Flip activ
    POST   /api/pms/optimizator/{hotelId}/reset   # Restore default rules

Config persists in `hoteluri.setari_admin.optimizator_tarif` (JSON sub-key).
Rule validation: `min >= 0`, `max > min`, `max <= 100`, `-50 <= extra <= 200`.

### Booking Reviews — [Admin]

    GET    /api/bookingreviews/                           # List reviews (?propertyId=&hotelId=&canalId=&page=&pageSize=)
    GET    /api/bookingreviews/{reviewId}                 # Get single review by ID (?propertyId=&hotelId=&canalId=)
    POST   /api/bookingreviews/{reviewId}/reply           # Post property reply (?propertyId=&hotelId=&canalId=)
    GET    /api/bookingreviews/score                      # Review-only score for property (?propertyId=&hotelId=&canalId=)

Pass-through to `supply-xml.booking.com/review-api`. Reviews must not be republished publicly per Booking's terms.

### Booking Property Scores — [Admin]

    GET    /api/bookingscores/                            # Summary for multiple properties (paginated, ?hotelId=&canalId=&page=&pageSize=)
    GET    /api/bookingscores/{propertyId}                # Per-property score breakdown (?hotelId=&canalId=)

Pass-through to `supply-xml.booking.com/property-scores`.

Both review and score endpoints resolve the Booking `propertyId` from `hotel_id_canal` automatically when
`?hotelId=&canalId=` are supplied. The JWT is injected from `setari.booking_token`; a 401 triggers one
automatic token refresh before bubbling up as `502 Bad Gateway`.

### Booking Promotions — [Consumer]

    GET    /api/pms/connections/{id}/promotions                     # Live list (auto-aggregated)
    GET    /api/pms/connections/{id}/promotion-types                # Capabilities (per-channel discount ranges, campaign windows)
    GET    /api/pms/connections/{id}/promotions/{promoId}           # Single promotion
    POST   /api/pms/connections/{id}/promotions                     # Create (no id) / update (id in body)
    POST   /api/pms/connections/{id}/promotions/{promoId}/activate  # Reactivate
    DELETE /api/pms/connections/{id}/promotions/{promoId}           # Deactivate (soft)

Thin 1:1 Booking Supply-XML adapter. Ownership + Booking-only (`canal_id=6`) enforced server-side; the
Booking `propertyId` is resolved from `hotel_id_canal` (never a client param). Responses mirror Booking's
shape (camelCase), no normalization. Booking content faults surface as `{ faults:[{code,message}] }` (422);
gate failures return `{ error, code }`.

### Health & Version (no auth required)

    GET /health
    # { "status": "healthy", "database": "connected" }

    GET /version
    # { "version": "0.5.0", "sha": "abc1234", "branch": "master", "buildTime": "2026-05-25T..." }

## Important Notes

- Always call `/health` first to confirm connectivity before multi-step workflows.
- The `expira` field in responses is a **Unix timestamp** (seconds).
  When creating or extending, send a date string like `"2027-01-01"`.
- HTTP status codes: 200 success, 201 created, 401 unauthorized, 404 not found, 500 server error.

Changelog

v0.5.17

2026-11-03 — patch

Fixed

  • /version reports the build’s commit and branch on every host.

Changed

  • The interactive API documentation (/scalar, /openapi) is no longer served publicly.

Security

  • Security fix.

v0.5.16

2026-10-16 — patch

Fixed

  • Extra-bed and children prices sent with POST /api/pms/prices now reach the correct 4booking rate plans.

Added

  • New warnings reasons on 4booking extras: extras_no_ob_plan and extras_non_numeric_id.

v0.5.15

2026-10-12 — minor

Added

  • GET /api/pms/connections/{id}/channel-rooms: the channel’s rooms and rate plans, read live, for room mapping.
  • POST /api/pms/connections/{id}/rooms accepts the rate plans of each room (concepte).

Security

  • Security fix.

v0.5.14

2026-09-25 — patch

Fixed

  • POST /api/pms/restrictions no longer fails on some channel mappings.

v0.5.13

2026-08-31 — security

Security

  • Security fix.

Added

  • GET and PUT /api/pms/connections/{id} to read and edit a channel connection.

v0.5.12

2026-07-28 — patch

Fixed

  • POST /api/pms/init removes child categories the PMS no longer sends and reports them in removedCategoriiCopiiIds.

v0.5.11

2026-07-27 — patch

Added

  • Optional hnextConfig on POST /api/hotels/add and PUT /api/hotels/{id} to set a hotel’s HNext credentials.

v0.5.10

2026-07-27 — patch

Changed

  • Incidents are posted to HNext without a location code; the location code setting is now optional.

v0.5.9

2026-07-27 — patch

Added

  • Resolving an incident in HNext now records the resolution note and who resolved it.

v0.5.8

2026-07-24 — patch

Added

  • Each incident sent to HNext carries its own resolve callback.

v0.5.7

2026-07-22 — minor

Added

  • HNext Incidente integration: channel-sync problems that need an operator appear in the hotel’s HNext app.

Built With

.NET 10 C# MySQL Docker Azure App Service Bitbucket Pipelines