> For the complete documentation index, see [llms.txt](https://mobile-calendar.gitbook.io/v1/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mobile-calendar.gitbook.io/v1/rest-api/additional-services.md).

# Additional Services

Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc.

## List additional services (paginated)

> Returns the account's additional services (add-ons such as parking, breakfast, late check-out) that can be attached to reservations via \`additionalServices\[].additionalServiceId\`. Deleted services are not returned. Required scope: \`additionalServices.read\`.

```json
{"openapi":"3.0.0","info":{"title":"Public REST API v1 – mobile-calendar.com","version":"1.0.0"},"tags":[{"name":"additional-services","description":"Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc."}],"servers":[{"url":"https://api.mobile-calendar.com/v1/public","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"Pass the token in header: Authorization: Bearer <JWT>","bearerFormat":"JWT","scheme":"bearer"}},"parameters":{"PageParam":{"name":"page","in":"query","description":"Page number (>=1)","required":false,"schema":{"type":"integer","default":1,"minimum":1}},"LimitParam":{"name":"limit","in":"query","description":"Page size (1–200)","required":false,"schema":{"type":"integer","default":25,"maximum":200,"minimum":1}}},"schemas":{"AdditionalServiceListResponse":{"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AdditionalService"}},"meta":{"$ref":"#/components/schemas/MetaWithPagination"}},"type":"object"},"AdditionalService":{"description":"Additional service (add-on) that can be attached to a reservation — e.g. parking, breakfast, late check-out. Reservations reference it by `additionalServiceId` in their `additionalServices` array. `description` is optional — its `default` may be an empty string.","required":["additionalServiceId","name","description","period","chargeType","priceAdult","priceChildren","taxRate","bookingEngine","editDate"],"properties":{"additionalServiceId":{"type":"integer"},"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"description":"How the price is multiplied: `PER_NIGHT` — price × nights; `PER_STAY` — once per reservation; `PER_UNIT` — price × quantity chosen on the reservation (for `PER_UNIT` the `chargeType` is ignored and only `priceAdult` is used).","type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"description":"`PER_SERVICE` — one price for the whole service (`priceAdult`); `PER_PERSON` — `priceAdult` per adult plus `priceChildren` per child.","type":"string","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"description":"Price in the account currency. For `PER_SERVICE` this is the price of the service; for `PER_PERSON` the price per adult.","type":"number","format":"float"},"priceChildren":{"description":"Price per child — used only when `chargeType` is `PER_PERSON`.","type":"number","format":"float"},"taxRate":{"description":"VAT rate label used on invoices (e.g. `23`, `8`, `zw`). `null` — not set.","type":"string","maxLength":5,"nullable":true},"bookingEngine":{"$ref":"#/components/schemas/AdditionalServiceBookingEngine"},"editDate":{"description":"Last modification time (UTC, ISO 8601) — same format as `addDate`/`editDate` of other resources.","type":"string","format":"date-time"}},"type":"object"},"LocalizedText":{"description":"Text with optional translations. `default` is mandatory and is used whenever no translation exists for the guest's language; every other key is an ISO 639-1 language code (e.g. `pl`, `en`, `de`).","required":["default"],"properties":{"default":{"type":"string"}},"type":"object","additionalProperties":{"type":"string"}},"AdditionalServiceBookingEngine":{"description":"How the service is offered in the online booking engine (widget, SRO) — the panel's Booking engine → Additional services screen. Change it with PATCH (`bookingEngine`, see AdditionalServiceUpdateRequest); POST ignores it (a new service is not offered in the widget until you set it).","required":["option","shareInOffer","rooms","roomTypes"],"properties":{"option":{"description":"`NONE` — not offered in the widget; `MANDATORY` — always added to the reservation and charged; `INCLUDED_IN_PRICE` — always added, shown as included in the price (not charged); `OPTIONAL` — the guest can add it; `ON_SITE` — shown with its price as payable at the property (informational only, not added to the reservation).","type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]},"shareInOffer":{"description":"Whether the service is shown in the widget at all.","type":"boolean"},"rooms":{"description":"Room IDs the service applies to. `null` — all rooms; `[]` — no rooms; a list — only those rooms.","type":"array","items":{"type":"integer"},"nullable":true},"roomTypes":{"description":"Room type IDs the service applies to. Same semantics as `rooms`.","type":"array","items":{"type":"integer"},"nullable":true}},"type":"object"},"MetaWithPagination":{"description":"Pagination parameters with request tracking in list responses.","required":["totalItems","currentPage","totalPages","itemsPerPage","ruid"],"properties":{"totalItems":{"type":"integer","minimum":0},"currentPage":{"type":"integer","minimum":1},"totalPages":{"type":"integer","minimum":0},"itemsPerPage":{"type":"integer","minimum":1},"ruid":{"description":"Request Unique ID","type":"string","format":"uuid"}},"type":"object"},"ApiProblem401":{"description":"Missing authentication or invalid credentials.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"401 Unauthorized","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblemBase":{"description":"RFC 7807 Problem Details (base schema).","required":["type","title","status","detail","instance"],"properties":{"type":{"description":"RFC 7807 base — DO NOT use directly in endpoints.\nIn endpoints reference ApiProblem400/401/403/409/422/429/500.","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"},"ApiProblem403":{"description":"Authenticated user but no access.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"403 Forbidden","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem422":{"description":"Input data validation error.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"422 Unprocessable Entity (validation)","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"},"errors":{"description":"Map: field name → error message(s)","type":"object","additionalProperties":{"$ref":"#/components/schemas/ErrorValue"}}},"type":"object"}]},"ErrorValue":{"description":"Single error message or list of messages.","oneOf":[{"description":"Error value in error map can be:\n- single string, or\n- array of strings (multiple messages for one field).","type":"string"},{"type":"array","items":{"type":"string"}}]}}},"paths":{"/additional-services":{"get":{"tags":["additional-services"],"summary":"List additional services (paginated)","description":"Returns the account's additional services (add-ons such as parking, breakfast, late check-out) that can be attached to reservations via `additionalServices[].additionalServiceId`. Deleted services are not returned. Required scope: `additionalServices.read`.","operationId":"listAdditionalServices","parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/LimitParam"},{"name":"search","in":"query","description":"Search in the service name (all translations)","required":false,"schema":{"type":"string","maxLength":255}},{"name":"period","in":"query","description":"Filter by billing period","required":false,"schema":{"type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]}},{"name":"chargeType","in":"query","description":"Filter by charge type","required":false,"schema":{"type":"string","enum":["PER_SERVICE","PER_PERSON"]}},{"name":"bookingEngineOption","in":"query","description":"Filter by how the service is offered in the online booking engine","required":false,"schema":{"type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]}},{"name":"orderBy","in":"query","description":"Sort field","required":false,"schema":{"type":"string","default":"additionalServiceId","enum":["additionalServiceId","name","priceAdult","editDate"]}},{"name":"orderType","in":"query","description":"Sort direction","required":false,"schema":{"type":"string","default":"ASC","enum":["ASC","DESC"]}}],"responses":{"200":{"description":"List of additional services","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem401"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem403"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem422"}}}}}}}}}
```

## Create additional service

> Creates an additional service. \`name.default\` is required (each translation up to 255 bytes, description up to 5000 bytes per value); prices are non-negative with at most 2 decimals. After creation it can be attached to reservations (\`additionalServices\[].additionalServiceId\`). It is NOT offered in the online booking engine (SRO) until configured — the \`bookingEngine\` section is read-only here; set it afterwards with PATCH (\`bookingEngine\`) or in the panel. Required scope: \`additionalServices.create\`.

```json
{"openapi":"3.0.0","info":{"title":"Public REST API v1 – mobile-calendar.com","version":"1.0.0"},"tags":[{"name":"additional-services","description":"Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc."}],"servers":[{"url":"https://api.mobile-calendar.com/v1/public","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"Pass the token in header: Authorization: Bearer <JWT>","bearerFormat":"JWT","scheme":"bearer"}},"schemas":{"AdditionalServiceCreateRequest":{"description":"New additional service. `name` — shown to the guest and on invoices; `default` is required and must not be empty, each value up to 255 bytes. `description` — optional, `default` may be empty, each value up to 5000 bytes. Texts are plain text (HTML is escaped). Prices default to 0, `chargeType` to `PER_SERVICE`. The `bookingEngine` section cannot be set here — it is managed in the panel.","required":["name","period"],"properties":{"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"type":"string","default":"PER_SERVICE","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"description":"Non-negative, at most 2 decimal places.","type":"number","format":"float","default":0,"maximum":9999999.99,"minimum":0},"priceChildren":{"description":"Non-negative, at most 2 decimal places. Used only with `chargeType: PER_PERSON`.","type":"number","format":"float","default":0,"maximum":9999999.99,"minimum":0},"taxRate":{"description":"VAT rate label (e.g. `23`, `8`, `zw`). Omit or send `null` for no rate.","type":"string","maxLength":5,"nullable":true}},"type":"object"},"LocalizedText":{"description":"Text with optional translations. `default` is mandatory and is used whenever no translation exists for the guest's language; every other key is an ISO 639-1 language code (e.g. `pl`, `en`, `de`).","required":["default"],"properties":{"default":{"type":"string"}},"type":"object","additionalProperties":{"type":"string"}},"AdditionalServiceResponse":{"description":"Single additional service response with metadata","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/AdditionalService"},"meta":{"$ref":"#/components/schemas/MetaWithRuid"}},"type":"object"},"AdditionalService":{"description":"Additional service (add-on) that can be attached to a reservation — e.g. parking, breakfast, late check-out. Reservations reference it by `additionalServiceId` in their `additionalServices` array. `description` is optional — its `default` may be an empty string.","required":["additionalServiceId","name","description","period","chargeType","priceAdult","priceChildren","taxRate","bookingEngine","editDate"],"properties":{"additionalServiceId":{"type":"integer"},"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"description":"How the price is multiplied: `PER_NIGHT` — price × nights; `PER_STAY` — once per reservation; `PER_UNIT` — price × quantity chosen on the reservation (for `PER_UNIT` the `chargeType` is ignored and only `priceAdult` is used).","type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"description":"`PER_SERVICE` — one price for the whole service (`priceAdult`); `PER_PERSON` — `priceAdult` per adult plus `priceChildren` per child.","type":"string","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"description":"Price in the account currency. For `PER_SERVICE` this is the price of the service; for `PER_PERSON` the price per adult.","type":"number","format":"float"},"priceChildren":{"description":"Price per child — used only when `chargeType` is `PER_PERSON`.","type":"number","format":"float"},"taxRate":{"description":"VAT rate label used on invoices (e.g. `23`, `8`, `zw`). `null` — not set.","type":"string","maxLength":5,"nullable":true},"bookingEngine":{"$ref":"#/components/schemas/AdditionalServiceBookingEngine"},"editDate":{"description":"Last modification time (UTC, ISO 8601) — same format as `addDate`/`editDate` of other resources.","type":"string","format":"date-time"}},"type":"object"},"AdditionalServiceBookingEngine":{"description":"How the service is offered in the online booking engine (widget, SRO) — the panel's Booking engine → Additional services screen. Change it with PATCH (`bookingEngine`, see AdditionalServiceUpdateRequest); POST ignores it (a new service is not offered in the widget until you set it).","required":["option","shareInOffer","rooms","roomTypes"],"properties":{"option":{"description":"`NONE` — not offered in the widget; `MANDATORY` — always added to the reservation and charged; `INCLUDED_IN_PRICE` — always added, shown as included in the price (not charged); `OPTIONAL` — the guest can add it; `ON_SITE` — shown with its price as payable at the property (informational only, not added to the reservation).","type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]},"shareInOffer":{"description":"Whether the service is shown in the widget at all.","type":"boolean"},"rooms":{"description":"Room IDs the service applies to. `null` — all rooms; `[]` — no rooms; a list — only those rooms.","type":"array","items":{"type":"integer"},"nullable":true},"roomTypes":{"description":"Room type IDs the service applies to. Same semantics as `rooms`.","type":"array","items":{"type":"integer"},"nullable":true}},"type":"object"},"MetaWithRuid":{"description":"Metadata with request tracking.","required":["ruid"],"properties":{"ruid":{"description":"Request Unique ID","type":"string","format":"uuid"}},"type":"object"},"ApiProblem400":{"description":"Request syntax/format error.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"400 Bad Request","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblemBase":{"description":"RFC 7807 Problem Details (base schema).","required":["type","title","status","detail","instance"],"properties":{"type":{"description":"RFC 7807 base — DO NOT use directly in endpoints.\nIn endpoints reference ApiProblem400/401/403/409/422/429/500.","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"},"ApiProblem401":{"description":"Missing authentication or invalid credentials.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"401 Unauthorized","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem403":{"description":"Authenticated user but no access.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"403 Forbidden","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem422":{"description":"Input data validation error.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"422 Unprocessable Entity (validation)","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"},"errors":{"description":"Map: field name → error message(s)","type":"object","additionalProperties":{"$ref":"#/components/schemas/ErrorValue"}}},"type":"object"}]},"ErrorValue":{"description":"Single error message or list of messages.","oneOf":[{"description":"Error value in error map can be:\n- single string, or\n- array of strings (multiple messages for one field).","type":"string"},{"type":"array","items":{"type":"string"}}]}}},"paths":{"/additional-services":{"post":{"tags":["additional-services"],"summary":"Create additional service","description":"Creates an additional service. `name.default` is required (each translation up to 255 bytes, description up to 5000 bytes per value); prices are non-negative with at most 2 decimals. After creation it can be attached to reservations (`additionalServices[].additionalServiceId`). It is NOT offered in the online booking engine (SRO) until configured — the `bookingEngine` section is read-only here; set it afterwards with PATCH (`bookingEngine`) or in the panel. Required scope: `additionalServices.create`.","operationId":"createAdditionalService","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceCreateRequest"}}}},"responses":{"201":{"description":"Created","headers":{"Location":{"description":"URL of the new resource","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem400"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem401"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem403"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem422"}}}}}}}}}
```

## Get additional service by ID

> Required scope: \`additionalServices.read\`.

```json
{"openapi":"3.0.0","info":{"title":"Public REST API v1 – mobile-calendar.com","version":"1.0.0"},"tags":[{"name":"additional-services","description":"Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc."}],"servers":[{"url":"https://api.mobile-calendar.com/v1/public","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"Pass the token in header: Authorization: Bearer <JWT>","bearerFormat":"JWT","scheme":"bearer"}},"schemas":{"AdditionalServiceResponse":{"description":"Single additional service response with metadata","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/AdditionalService"},"meta":{"$ref":"#/components/schemas/MetaWithRuid"}},"type":"object"},"AdditionalService":{"description":"Additional service (add-on) that can be attached to a reservation — e.g. parking, breakfast, late check-out. Reservations reference it by `additionalServiceId` in their `additionalServices` array. `description` is optional — its `default` may be an empty string.","required":["additionalServiceId","name","description","period","chargeType","priceAdult","priceChildren","taxRate","bookingEngine","editDate"],"properties":{"additionalServiceId":{"type":"integer"},"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"description":"How the price is multiplied: `PER_NIGHT` — price × nights; `PER_STAY` — once per reservation; `PER_UNIT` — price × quantity chosen on the reservation (for `PER_UNIT` the `chargeType` is ignored and only `priceAdult` is used).","type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"description":"`PER_SERVICE` — one price for the whole service (`priceAdult`); `PER_PERSON` — `priceAdult` per adult plus `priceChildren` per child.","type":"string","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"description":"Price in the account currency. For `PER_SERVICE` this is the price of the service; for `PER_PERSON` the price per adult.","type":"number","format":"float"},"priceChildren":{"description":"Price per child — used only when `chargeType` is `PER_PERSON`.","type":"number","format":"float"},"taxRate":{"description":"VAT rate label used on invoices (e.g. `23`, `8`, `zw`). `null` — not set.","type":"string","maxLength":5,"nullable":true},"bookingEngine":{"$ref":"#/components/schemas/AdditionalServiceBookingEngine"},"editDate":{"description":"Last modification time (UTC, ISO 8601) — same format as `addDate`/`editDate` of other resources.","type":"string","format":"date-time"}},"type":"object"},"LocalizedText":{"description":"Text with optional translations. `default` is mandatory and is used whenever no translation exists for the guest's language; every other key is an ISO 639-1 language code (e.g. `pl`, `en`, `de`).","required":["default"],"properties":{"default":{"type":"string"}},"type":"object","additionalProperties":{"type":"string"}},"AdditionalServiceBookingEngine":{"description":"How the service is offered in the online booking engine (widget, SRO) — the panel's Booking engine → Additional services screen. Change it with PATCH (`bookingEngine`, see AdditionalServiceUpdateRequest); POST ignores it (a new service is not offered in the widget until you set it).","required":["option","shareInOffer","rooms","roomTypes"],"properties":{"option":{"description":"`NONE` — not offered in the widget; `MANDATORY` — always added to the reservation and charged; `INCLUDED_IN_PRICE` — always added, shown as included in the price (not charged); `OPTIONAL` — the guest can add it; `ON_SITE` — shown with its price as payable at the property (informational only, not added to the reservation).","type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]},"shareInOffer":{"description":"Whether the service is shown in the widget at all.","type":"boolean"},"rooms":{"description":"Room IDs the service applies to. `null` — all rooms; `[]` — no rooms; a list — only those rooms.","type":"array","items":{"type":"integer"},"nullable":true},"roomTypes":{"description":"Room type IDs the service applies to. Same semantics as `rooms`.","type":"array","items":{"type":"integer"},"nullable":true}},"type":"object"},"MetaWithRuid":{"description":"Metadata with request tracking.","required":["ruid"],"properties":{"ruid":{"description":"Request Unique ID","type":"string","format":"uuid"}},"type":"object"},"ApiProblem401":{"description":"Missing authentication or invalid credentials.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"401 Unauthorized","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblemBase":{"description":"RFC 7807 Problem Details (base schema).","required":["type","title","status","detail","instance"],"properties":{"type":{"description":"RFC 7807 base — DO NOT use directly in endpoints.\nIn endpoints reference ApiProblem400/401/403/409/422/429/500.","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"},"ApiProblem403":{"description":"Authenticated user but no access.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"403 Forbidden","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem404":{"description":"Resource specified in the request was not found.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"404 Not Found","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]}}},"paths":{"/additional-services/{id}":{"get":{"tags":["additional-services"],"summary":"Get additional service by ID","description":"Required scope: `additionalServices.read`.","operationId":"getAdditionalService","parameters":[{"name":"id","in":"path","description":"Additional service ID","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem401"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem403"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem404"}}}}}}}}}
```

## Delete additional service

> Deletes an additional service (soft delete — it disappears from the list and from the booking engine). Reservations that already contain the service keep it with the frozen price. Required scope: \`additionalServices.delete\`.

```json
{"openapi":"3.0.0","info":{"title":"Public REST API v1 – mobile-calendar.com","version":"1.0.0"},"tags":[{"name":"additional-services","description":"Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc."}],"servers":[{"url":"https://api.mobile-calendar.com/v1/public","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"Pass the token in header: Authorization: Bearer <JWT>","bearerFormat":"JWT","scheme":"bearer"}},"schemas":{"ApiProblem401":{"description":"Missing authentication or invalid credentials.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"401 Unauthorized","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblemBase":{"description":"RFC 7807 Problem Details (base schema).","required":["type","title","status","detail","instance"],"properties":{"type":{"description":"RFC 7807 base — DO NOT use directly in endpoints.\nIn endpoints reference ApiProblem400/401/403/409/422/429/500.","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"},"ApiProblem403":{"description":"Authenticated user but no access.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"403 Forbidden","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem404":{"description":"Resource specified in the request was not found.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"404 Not Found","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]}}},"paths":{"/additional-services/{id}":{"delete":{"tags":["additional-services"],"summary":"Delete additional service","description":"Deletes an additional service (soft delete — it disappears from the list and from the booking engine). Reservations that already contain the service keep it with the frozen price. Required scope: `additionalServices.delete`.","operationId":"deleteAdditionalService","parameters":[{"name":"id","in":"path","description":"Additional service ID","required":true,"schema":{"type":"integer"}}],"responses":{"204":{"description":"Deleted successfully","headers":{"RUID":{"description":"Request unique identifier","schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem401"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem403"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem404"}}}}}}}}}
```

## Update additional service (partial update)

> Updates one or more fields of an additional service. Only the fields provided in the request body are changed. Changing the price does not affect reservations that already contain the service (their price is frozen at the time it was added). The \`bookingEngine\` object shares the service in the online booking engine (SRO) for chosen rooms / room types — exactly what the panel's Booking engine → Additional services screen saves; an employee additionally needs the booking engine permission. Required scope: \`additionalServices.update\`.

```json
{"openapi":"3.0.0","info":{"title":"Public REST API v1 – mobile-calendar.com","version":"1.0.0"},"tags":[{"name":"additional-services","description":"Additional services (add-ons) that can be attached to reservations: parking, breakfast, late check-out, etc."}],"servers":[{"url":"https://api.mobile-calendar.com/v1/public","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"Pass the token in header: Authorization: Bearer <JWT>","bearerFormat":"JWT","scheme":"bearer"}},"schemas":{"AdditionalServiceUpdateRequest":{"description":"Partial update — only the fields present in the body are changed. A field that is sent must not be null (exception: `taxRate: null` clears the rate). Sending `name` or `description` replaces the whole translations object, not single languages (same limits as on create: 255 / 5000 bytes per value). `bookingEngine` changes how the service is offered in the online booking engine (SRO) — only the keys you send; keys sent with the currently saved value are ignored (a GET → PATCH round trip of the whole object leaves the SRO settings untouched and needs no extra permission). An actual change requires, for an employee, the booking engine permission (403 otherwise).","properties":{"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"type":"string","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"type":"number","format":"float","maximum":9999999.99,"minimum":0},"priceChildren":{"type":"number","format":"float","maximum":9999999.99,"minimum":0},"taxRate":{"type":"string","maxLength":5,"nullable":true},"bookingEngine":{"description":"Booking engine (SRO) offer of the service — same settings as the panel's Booking engine → Additional services. To let guests add the service in the widget's Extras step: `option: OPTIONAL` + `shareInOffer: true` + the room in `rooms`. The widget sells a room that belongs to a room type AS THAT TYPE, so for such a room put its `roomTypeId` (from listRooms / getRoomTypes) in `roomTypes`; a room without a type goes to `rooms`. When extending a specific list, send the current ids plus the new one (read them from getAdditionalService) — the list is replaced, not merged.","properties":{"option":{"description":"`NONE` — not offered; `MANDATORY` — always added and charged; `INCLUDED_IN_PRICE` — always added, shown as included; `OPTIONAL` — the guest may add it; `ON_SITE` — shown as payable at the property (not added to the reservation).","type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]},"shareInOffer":{"description":"Show the service in the widget at all (false hides it regardless of `option`).","type":"boolean"},"rooms":{"description":"Room ids (rooms without a room type). `null` — all rooms, `[]` — none, list — only these (replaces the current list).","type":"array","items":{"type":"integer"},"nullable":true},"roomTypes":{"description":"Room type ids. Same semantics as `rooms`.","type":"array","items":{"type":"integer"},"nullable":true}},"type":"object"}},"type":"object"},"LocalizedText":{"description":"Text with optional translations. `default` is mandatory and is used whenever no translation exists for the guest's language; every other key is an ISO 639-1 language code (e.g. `pl`, `en`, `de`).","required":["default"],"properties":{"default":{"type":"string"}},"type":"object","additionalProperties":{"type":"string"}},"AdditionalServiceResponse":{"description":"Single additional service response with metadata","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/AdditionalService"},"meta":{"$ref":"#/components/schemas/MetaWithRuid"}},"type":"object"},"AdditionalService":{"description":"Additional service (add-on) that can be attached to a reservation — e.g. parking, breakfast, late check-out. Reservations reference it by `additionalServiceId` in their `additionalServices` array. `description` is optional — its `default` may be an empty string.","required":["additionalServiceId","name","description","period","chargeType","priceAdult","priceChildren","taxRate","bookingEngine","editDate"],"properties":{"additionalServiceId":{"type":"integer"},"name":{"$ref":"#/components/schemas/LocalizedText"},"description":{"$ref":"#/components/schemas/LocalizedText"},"period":{"description":"How the price is multiplied: `PER_NIGHT` — price × nights; `PER_STAY` — once per reservation; `PER_UNIT` — price × quantity chosen on the reservation (for `PER_UNIT` the `chargeType` is ignored and only `priceAdult` is used).","type":"string","enum":["PER_NIGHT","PER_STAY","PER_UNIT"]},"chargeType":{"description":"`PER_SERVICE` — one price for the whole service (`priceAdult`); `PER_PERSON` — `priceAdult` per adult plus `priceChildren` per child.","type":"string","enum":["PER_SERVICE","PER_PERSON"]},"priceAdult":{"description":"Price in the account currency. For `PER_SERVICE` this is the price of the service; for `PER_PERSON` the price per adult.","type":"number","format":"float"},"priceChildren":{"description":"Price per child — used only when `chargeType` is `PER_PERSON`.","type":"number","format":"float"},"taxRate":{"description":"VAT rate label used on invoices (e.g. `23`, `8`, `zw`). `null` — not set.","type":"string","maxLength":5,"nullable":true},"bookingEngine":{"$ref":"#/components/schemas/AdditionalServiceBookingEngine"},"editDate":{"description":"Last modification time (UTC, ISO 8601) — same format as `addDate`/`editDate` of other resources.","type":"string","format":"date-time"}},"type":"object"},"AdditionalServiceBookingEngine":{"description":"How the service is offered in the online booking engine (widget, SRO) — the panel's Booking engine → Additional services screen. Change it with PATCH (`bookingEngine`, see AdditionalServiceUpdateRequest); POST ignores it (a new service is not offered in the widget until you set it).","required":["option","shareInOffer","rooms","roomTypes"],"properties":{"option":{"description":"`NONE` — not offered in the widget; `MANDATORY` — always added to the reservation and charged; `INCLUDED_IN_PRICE` — always added, shown as included in the price (not charged); `OPTIONAL` — the guest can add it; `ON_SITE` — shown with its price as payable at the property (informational only, not added to the reservation).","type":"string","enum":["NONE","MANDATORY","INCLUDED_IN_PRICE","OPTIONAL","ON_SITE"]},"shareInOffer":{"description":"Whether the service is shown in the widget at all.","type":"boolean"},"rooms":{"description":"Room IDs the service applies to. `null` — all rooms; `[]` — no rooms; a list — only those rooms.","type":"array","items":{"type":"integer"},"nullable":true},"roomTypes":{"description":"Room type IDs the service applies to. Same semantics as `rooms`.","type":"array","items":{"type":"integer"},"nullable":true}},"type":"object"},"MetaWithRuid":{"description":"Metadata with request tracking.","required":["ruid"],"properties":{"ruid":{"description":"Request Unique ID","type":"string","format":"uuid"}},"type":"object"},"ApiProblem400":{"description":"Request syntax/format error.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"400 Bad Request","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblemBase":{"description":"RFC 7807 Problem Details (base schema).","required":["type","title","status","detail","instance"],"properties":{"type":{"description":"RFC 7807 base — DO NOT use directly in endpoints.\nIn endpoints reference ApiProblem400/401/403/409/422/429/500.","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"},"ApiProblem401":{"description":"Missing authentication or invalid credentials.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"401 Unauthorized","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem403":{"description":"Authenticated user but no access.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"403 Forbidden","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem404":{"description":"Resource specified in the request was not found.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"404 Not Found","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"}},"type":"object"}]},"ApiProblem422":{"description":"Input data validation error.","allOf":[{"$ref":"#/components/schemas/ApiProblemBase"},{"properties":{"type":{"description":"422 Unprocessable Entity (validation)","type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"},"errors":{"description":"Map: field name → error message(s)","type":"object","additionalProperties":{"$ref":"#/components/schemas/ErrorValue"}}},"type":"object"}]},"ErrorValue":{"description":"Single error message or list of messages.","oneOf":[{"description":"Error value in error map can be:\n- single string, or\n- array of strings (multiple messages for one field).","type":"string"},{"type":"array","items":{"type":"string"}}]}}},"paths":{"/additional-services/{id}":{"patch":{"tags":["additional-services"],"summary":"Update additional service (partial update)","description":"Updates one or more fields of an additional service. Only the fields provided in the request body are changed. Changing the price does not affect reservations that already contain the service (their price is frozen at the time it was added). The `bookingEngine` object shares the service in the online booking engine (SRO) for chosen rooms / room types — exactly what the panel's Booking engine → Additional services screen saves; an employee additionally needs the booking engine permission. Required scope: `additionalServices.update`.","operationId":"updateAdditionalService","parameters":[{"name":"id","in":"path","description":"Additional service ID","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceUpdateRequest"}}}},"responses":{"200":{"description":"Updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdditionalServiceResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem400"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem401"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem403"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem404"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiProblem422"}}}}}}}}}
```
