APRO Dokumentation · Stand 6. November 2026

Hotel API (PMS)

Zuletzt aktualisiert: 5. November 2026ca. 5 Min. Lesezeit

PDF erzeugen

The Hotel API is a two-way bridge between an APRO point-of-sale and any Property Management System (PMS). The PMS pushes reservations into the POS so that guests can charge to their room; the POS exposes those charges back to the PMS so they land on the final hotel invoice.

Typical flow

PMS                                       APRO POS
 │ 1. POST  /pms/reservations  ─────────▶ │   (upsert guest rooms)
 │                                        │
 │                                        │  guests charge to room…
 │                                        │
 │ 2. GET   /pms/charges?hotelId=…  ─────▶│
 │ ◀─── charges (and optionally receipts) │
 │                                        │
 │ 3. POST  /pms/confirm-charges  ───────▶│   (ack; won't be resent)
 │                                        │
 │ 4. DELETE /pms/reservations?…  ───────▶│   (on check-out / close-out)

Step 2 is the PMS's polling loop. Steps 1 and 4 are driven by events in the PMS. Step 3 must always follow a successful poll — otherwise the same charges will be returned again on the next poll.

1. Upsert reservations

Push the current list of active reservations into the POS. Keys are hotelId + Id + guestId; existing rows are updated in place.

POST https://cloudgateway.apro.at/hotelservice/api/v1/pms/reservations

Request body

Field

Type

Required

Description

reservations

Reservation[]

✅

One or more reservations.

Reservation

Field

Type

Required

Description

Id

string

✅

PMS-side reservation ID.

hotelId

string

✅

PMS tenant / property ID.

guestId

string

✅

PMS-side guest ID.

roomNr

string

✅

Assigned room number.

title

string

—

Mr., Mrs., etc.

firstName

string

—


lastName

string

—


arrival

ISO 8601

✅

Check-in timestamp.

departure

ISO 8601

✅

Check-out timestamp.

nrOfIndividuals

integer

—

Guest count, used for covers / buffet rules.

identifiers

Identifier[]

—

Keycard UIDs, NFC tags, room tablets etc. — any token the POS may receive when a guest wants to charge to a room.

Identifier

Field

Type

Description

value

string

The identifier value (keycard UID, token).

Example request

POST /hotelservice/api/v1/pms/reservations

{
  "reservations": [
    {
      "Id": "Aabc123",
      "hotelId": "1",
      "guestId": "Abc123",
      "roomNr": "Abc123",
      "title": "Mr.",
      "firstName": "Max",
      "lastName": "Mustermann",
      "arrival": "2026-04-02T14:00:00",
      "departure": "2026-04-04T14:00:00",
      "nrOfIndividuals": 1,
      "identifiers": [{ "value": "keycard-uid" }]
    }
  ]
}

Download: hotel-reservations-upsert.json

Example response

200 OK

{
  "newReservationsCount": 0,
  "checkedOutReservationsCount": 0,
  "updatedReservationsCount": 1,
  "state": 1,
  "isSuccessfull": true,
  "errorCode": 0,
  "message": null,
  "context": null
}

Download: hotel-reservations-response.json

Tip
Push the full active reservation set on every call, not deltas.
checkedOutReservationsCount reflects reservations the POS was tracking
but which are no longer in your payload — it removes them automatically.

2. Poll charges

Fetch everything booked against rooms since the last confirmed poll.

GET https://cloudgateway.apro.at/hotelservice/api/v1/pms/charges
    ?hotelId=1
    &excludeAlreadyExported=true

Query parameters

Name

Type

Required

Description

hotelId

string

✅

PMS tenant / property ID.

excludeAlreadyExported

bool

—

true = only return items not yet confirmed (the usual polling mode). false = re-fetch everything in the configured window.

Response shape

Each item has a chargeType that controls which fields are populated:

chargeType

Meaning

payments present?

Charge

An open line booked to the room (guest hasn't paid yet — POS is posting to the room folio).

no

Receipt

A closed receipt (guest settled at the POS; PMS may ignore or reconcile).

yes

Top-level envelope:

Field

Type

Description

page.limit

integer

Page size applied.

page.offset

integer

Offset into the backlog.

page.total

integer

Items still unconfirmed in total.

data

Item[]

Charges and receipts.

Item

Field

Type

Description

chargeType

`"Charge"

"Receipt"`

See table above.

bookDate

ISO 8601

When the line was booked in the POS.

receiptNr

integer

POS receipt number.

userId

integer

Operator / waiter ID.

userName

string

Operator name.

outlet

integer

Outlet ID (e.g. 1 = bar, 2 = restaurant).

tableNr

integer

Table number.

table

string

Table label.

totalAmount

decimal

Gross total of the line.

tip

decimal

Included tip.

businesscaseId

GUID

APRO transaction ID — use this as the transactionIds value to confirm.

reservationId

string | null

PMS reservation ID, for Charge items.

guestId

string | null

PMS guest ID.

roomNumber

string | null

Room number.

charges

LineItem[]

Individual article rows.

payments

Payment[]

Only on Receipt rows.

LineItem

Field

Type

Description

articleNr

integer

Product number.

articleName

string

Product name.

productgroupNr

integer

Category (Sparte) number.

productgroupName

string

Category name.

quantity

decimal

Quantity.

unitPrice

decimal

Gross unit price.

vatPercent

decimal

Applied VAT rate.

Example response

200 OK · charge + two receipts

{
  "page": { "limit": 3, "offset": 0, "total": 8096 },
  "data": [
    {
      "chargeType": "Charge",
      "bookDate": "2026-04-15T09:15:04.95",
      "receiptNr": 90,
      "userId": 20,
      "userName": "Johannes",
      "outlet": 1,
      "tableNr": 2,
      "table": "Bar 2",
      "totalAmount": 9.00,
      "tip": 0.30,
      "businesscaseId": "253c225f-7c4a-4d3f-80cd-63de4dbfca9e",
      "reservationId": "   15631",
      "guestId": "    6158",
      "roomNumber": "   414",
      "charges": [
        { "articleNr": 129,  "articleName": "Zipfer 0,2",     "productgroupName": "Bier",        "quantity": 1.00, "unitPrice": 1.10, "vatPercent": 20.00 },
        { "articleNr": 213,  "articleName": "Apfel ltg 0,5",  "productgroupName": "Flaschen AF", "quantity": 1.00, "unitPrice": 2.70, "vatPercent": 20.00 },
        { "articleNr": 1626, "articleName": "Würstel Pommes", "productgroupName": "Hauptspeise", "quantity": 1.00, "unitPrice": 4.90, "vatPercent": 10.00 }
      ]
    }
  ]
}

Download the full sample (Charge + two Receipts): hotel-charges-response.json

Caution
String fields like reservationId, guestId, roomNumber may be left-
padded with spaces when the POS stores them as fixed-width columns
(" 15631"). Trim on the PMS side before matching.

3. Confirm charges

Acknowledge the list you've successfully ingested. Once confirmed, the POS won't return those businesscaseIds on a subsequent poll with excludeAlreadyExported=true.

POST https://cloudgateway.apro.at/hotelservice/api/v1/pms/confirm-charges

Request body

Field

Type

Required

Description

hotelId

string

✅

PMS tenant / property ID.

transactionIds

GUID[]

✅

businesscaseId values from the previous /charges response.

POST /hotelservice/api/v1/pms/confirm-charges

{
  "hotelId": "1",
  "transactionIds": [
    "69F94B1A-3453-7017-8DDB-94E2175D0365",
    "155FFA87-DC19-EB1F-3DD8-540EF62A115D"
  ]
}

Download: hotel-confirm-charges.json

4. Remove a reservation

Explicit removal — useful at check-out or when the guest should no longer be able to charge to the room.

DELETE https://cloudgateway.apro.at/hotelservice/api/v1/pms/reservations
    ?hotelId=1
    &reservationId=Abc123
    &guestId=Abc123

All three query parameters are required. Either the targeted reservation is removed, or the call is a no-op if it doesn't exist.

Note
In practice the full-set upsert on step 1 is enough — any reservation
no longer present in the payload is checked out automatically
(checkedOutReservationsCount). Use this endpoint only when you need
an explicit out-of-band removal.

Idempotency & retries

  • POST /pms/reservations is idempotent on { hotelId, Id, guestId }. Re-sending the same payload converges to the same state.
  • POST /pms/confirm-charges is idempotent on transactionIds. Re-confirming an already-confirmed ID is a no-op.
  • Poll → confirm must be transactional in your own system: write the charges to your ledger first, then confirm. If the confirm fails, the same rows are returned next poll.

Errors

See Authentication → Error responses. On business-logic failures the response shape is:

{
  "isSuccessfull": false,
  "errorCode": 42,
  "message": "No reservation found for guestId 'Abc123'.",
  "context": { "guestId": "Abc123" }
}