API dokümantasyonu
Örnekler
Alıcı API'si v1: akış, kurallar, hata kataloğu ve örnekler – her örnek her derlemede test olarak çalışır.
El kitabındaki istekler, JetBrains ve VS Code REST istemcilerinin biçimindedir. “# @…” satırları, her örneği her derlemede yeni bir örneğe karşı çalıştıran testin doğrulamalarıdır.
01-preis.http
# Preisauskunft: /v1/price und /v1/prices (Handbuch Abschnitt 3).
# Zusicherungen "# @..." prueft cmd/tourapi-admin/handbuch_test.go (siehe README.md).
### preis-einzeln
# @status 200
# @feld totalCents = 18000
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"currency": "EUR",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### preis-guenstigstes-zimmer
# @status 200
# @feld totalCents = 12500
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### preis-guenstigstes-verfuegbares
# @status 200
# @feld room = "DZ"
# @feld availability.available = true
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-STOP",
"board": "RO",
"checkIn": "{{D10}}",
"checkOut": "{{D11}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### preis-alle-verpflegungen
# @status 200
# @feld rooms[0].boards[0].totalCents = 18000
POST {{baseUrl}}/v1/prices
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### preis-alle-verpflegungen-board-ignoriert
# @status 200
# @hinweis board: 'HB' wird bei /v1/prices ignoriert
POST {{baseUrl}}/v1/prices
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"board": "HB",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### preis-kundengruppe
# @status 200
# @feld totalCents = 14400
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{rabattKey}}
{
"hotel": "TEST-HOTEL-DISCOUNT",
"room": "DZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### preis-kind-bruchcent
# @status 200
# @feld totalCents = 48393
# @feld perTravellerCents[2] = 14433
# @feld breakdown[3].amountExact = "-13.485"
# @feld breakdown[3].amountCents = -1348
# @feld rounding.scope = "Person"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-KIND",
"room": "DZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}, {"age": 8}]}
}
02-suche.http
# Suche: /v1/search (Handbuch Abschnitt 4).
### suche-ziel
# @status 200
# @feld diagnostics.returned = 3
POST {{baseUrl}}/v1/search
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destination": "PMI",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### ziele
# @status 200
# @feld destinations[0].code = "ACE"
GET {{baseUrl}}/v1/destinations
X-Api-Key: {{apiKey}}
### suche-unbekanntes-ziel
# @status 422
# @feld errorCode = "ERR_UNKNOWN_DESTINATION"
POST {{baseUrl}}/v1/search
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destination": "pmi",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### suche-nicht-buchbare
# @status 200
POST {{baseUrl}}/v1/search
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destination": "IBZ",
"includeUnavailable": true,
"board": "RO",
"checkIn": "{{D11}}",
"checkOut": "{{D12}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### suche-seitenweise
# @status 200
# @feld diagnostics.considered = 3
# @merke nextCursor -> naechsteSeite
POST {{baseUrl}}/v1/search
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"pageSize": 3,
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
02b-suche-offen.http
# Offene Suche: /v1/search/open (Handbuch Abschnitt 4a).
### suche-offen
# @status 200
# @merke nextCursor -> offenCursor
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destinations": ["PMI"],
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"pageSize": 2
}
### suche-offen-weiter
# @status 200
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destinations": ["PMI"],
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"pageSize": 2,
"cursor": "{{offenCursor}}"
}
### suche-offen-je-nacht
# @status 200
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D13}}",
"nightsMin": 3,
"nightsMax": 5,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"boardTypes": ["BB", "HB"],
"sort": "pricePerNight",
"pageSize": 3
}
### suche-offen-stamm
# @status 200
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"destinations": ["PMI", "MAH"],
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"category": {"scheme": "stars", "min": 3.5},
"regions": ["Mallorca"],
"geo": {"lat": 39.57, "lon": 2.65, "radiusKm": 25}
}
### suche-offen-ohne-recht
# @status 403
# @feld errorCode = "ERR_OPEN_SEARCH_NOT_ALLOWED"
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{poolKey}}
{
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### suche-offen-fenster-zu-breit
# @status 422
# @feld errorCode = "ERR_WINDOW_TOO_WIDE"
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D30}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### suche-offen-ziel-nicht-erlaubt
# @status 403
# @feld errorCode = "ERR_DESTINATION_NOT_ALLOWED"
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{partnerKey}}
{
"destinations": ["PMI"],
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### suche-offen-filter-kaputt
# @status 422
# @feld errorCode = "ERR_BAD_FILTER"
POST {{baseUrl}}/v1/search/open
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D6}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"geo": {"lat": 39.57, "lon": 2.65, "radiusKm": 600}
}
02c-suche-termine.http
# Termin-Matrix /v1/search/open/dates (Handbuch Abschnitt 4b) und Grenzen /v1/limits (4c).
### suche-termine
# @status 200
POST {{baseUrl}}/v1/search/open/dates
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D1}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"maxTotalCents": 20000
}
### suche-termine-je-verpflegung
# @status 200
POST {{baseUrl}}/v1/search/open/dates
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D0}}",
"nightsMin": 2,
"nightsMax": 3,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"boards": ["BB", "HB"],
"perBoard": true
}
### suche-termine-zu-viele-zellen
# @status 422
# @feld errorCode = "ERR_SEARCH_TOO_BROAD"
POST {{baseUrl}}/v1/search/open/dates
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"arrivalFrom": "{{D0}}",
"arrivalTo": "{{D30}}",
"nightsMin": 1,
"nightsMax": 14,
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"perBoard": true
}
### grenzen
# @status 200
# @feld openSearch.allowed = true
GET {{baseUrl}}/v1/limits
X-Api-Key: {{apiKey}}
### grenzen-ohne-recht
# @status 200
# @feld openSearch.allowed = false
GET {{baseUrl}}/v1/limits
X-Api-Key: {{poolKey}}
03-buchung.http
# Buchung (B) und Buchungsinfo: /v1/book, /v1/booking (Handbuch Abschnitt 5).
# Reihenfolge zaehlt: die Beispiele laufen nacheinander gegen dieselbe Welt.
### buchen
# @status 200
# @feld booked = true
# @feld alreadyBooked = false
# @merke reference -> buchungsRef
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0001",
"reference": "KUNDE-4711",
"leadPaxName": "Erika Muster",
"metadata": {"correlationId": "kette-0815", "vermittler": "Filiale 12"},
"priceCheck": {
"board": "RO",
"currency": "EUR",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"expectedCents": 18000,
"tolerancePercent": 0
}
}
### buchen-wiederholt
# @status 200
# @feld alreadyBooked = true
# @feld reference = "{{buchungsRef}}"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0001",
"reference": "KUNDE-4711",
"leadPaxName": "Erika Muster",
"metadata": {"correlationId": "kette-0815", "vermittler": "Filiale 12"},
"priceCheck": {
"board": "RO",
"currency": "EUR",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"expectedCents": 18000,
"tolerancePercent": 0
}
}
### buchen-anderer-vorgang
# @status 409
# @feld errorCode = "ERR_IDEMPOTENCY_MISMATCH"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 2,
"idemKey": "BEISPIEL-0001"
}
### buchung-lesen
# @status 200
# @feld status = "confirmed"
GET {{baseUrl}}/v1/booking?ref={{buchungsRef}}
X-Api-Key: {{apiKey}}
### buchung-lesen-kundenreferenz
# @status 200
# @feld reference = "{{buchungsRef}}"
GET {{baseUrl}}/v1/booking?ref=KUNDE-4711
X-Api-Key: {{apiKey}}
### buchen-ohne-preispruefung
# @status 200
# @feld booked = true
# @merke reference -> ohnePreisRef
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D20}}",
"checkOut": "{{D21}}",
"quantity": 1,
"idemKey": "BEISPIEL-0010"
}
### buchung-lesen-ohne-preispruefung
# @status 200
GET {{baseUrl}}/v1/booking?ref={{ohnePreisRef}}
X-Api-Key: {{apiKey}}
### buchen-gleiche-kundenreferenz
# @status 200
# @feld alreadyBooked = false
# @merke reference -> zweiteRef
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D22}}",
"checkOut": "{{D23}}",
"quantity": 1,
"idemKey": "BEISPIEL-0011",
"reference": "KUNDE-4711"
}
### buchung-lesen-mehrdeutig
# @status 409
# @feld errorCode = "ERR_REFERENCE_AMBIGUOUS"
GET {{baseUrl}}/v1/booking?ref=KUNDE-4711
X-Api-Key: {{apiKey}}
### buchen-preis-geaendert
# @status 409
# @feld errorCode = "ERR_PRICE_DRIFT"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0002",
"priceCheck": {
"board": "RO",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"expectedCents": 17000,
"tolerancePercent": 2
}
}
### buchen-ausgebucht
# @status 422
# @feld errorCode = "ERR_SOLD_OUT"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-SOLD",
"room": "DZ",
"checkIn": "{{D13}}",
"checkOut": "{{D14}}",
"quantity": 1,
"idemKey": "BEISPIEL-0003"
}
### buchen-stop-sale
# @status 422
# @feld errorCode = "ERR_STOP_SALE"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-STOP",
"room": "DZ",
"checkIn": "{{D11}}",
"checkOut": "{{D12}}",
"quantity": 1,
"idemKey": "BEISPIEL-0004"
}
### buchen-zuteilung-erschoepft
# @status 422
# @feld errorCode = "ERR_GROUP_LIMIT"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{partnerKey}}
{
"hotel": "TEST-HOTEL-FREESALE",
"room": "DZ",
"checkIn": "{{D20}}",
"checkOut": "{{D21}}",
"quantity": 6,
"idemKey": "BEISPIEL-0005"
}
### buchen-preisgruppe
# @status 200
# @feld booked = true
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{rabattKey}}
{
"hotel": "TEST-HOTEL-DISCOUNT",
"room": "DZ",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"quantity": 1,
"idemKey": "BEISPIEL-0006"
}
04-storno.http
# Storno (S): /v1/cancel (Handbuch Abschnitt 6). Laeuft nach 03-buchung.http.
### stornieren
# @status 200
# @feld released = true
# @feld alreadyReleased = false
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "BEISPIEL-0001"}
### stornieren-wiederholt
# @status 200
# @feld alreadyReleased = true
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "BEISPIEL-0001"}
### buchung-lesen-storniert
# @status 200
# @feld status = "released"
GET {{baseUrl}}/v1/booking?ref={{buchungsRef}}
X-Api-Key: {{apiKey}}
### buchen-nach-storno
# @status 409
# @feld errorCode = "ERR_IDEM_KEY_RELEASED"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0001"
}
### stornieren-unbekannt
# @status 404
# @feld errorCode = "ERR_BOOKING_NOT_FOUND"
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "GIBT-ES-NICHT"}
05-fehler.http
# Fehler und Hinweise (Handbuch Abschnitt 2 und 7).
### fehler-ohne-key
# @status 401
# @feld errorCode = "ERR_UNAUTHORIZED"
POST {{baseUrl}}/v1/price
Content-Type: application/json
{}
### fehler-key-widerrufen
# @status 401
# @feld errorCode = "ERR_UNAUTHORIZED"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{gesperrterKey}}
{}
### fehler-methode
# @status 405
# @feld errorCode = "ERR_METHOD_NOT_ALLOWED"
GET {{baseUrl}}/v1/price
X-Api-Key: {{apiKey}}
### fehler-aufenthalt-zu-lang
# @status 422
# @feld errorCode = "ERR_STAY_TOO_LONG"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D31}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### fehler-anreise-vergangen
# @status 422
# @feld errorCode = "ERR_STAY_IN_PAST"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"board": "RO",
"checkIn": "{{gestern}}",
"checkOut": "{{heute}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### fehler-tippfehler-belegung
# @status 422
# @feld errorCode = "ERR_UNKNOWN_FIELD"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}, {"alter": 8}]}
}
### fehler-tippfehler-feld
# @status 422
# @feld errorCode = "ERR_BAD_DATE"
# @hinweis unbekanntes Feld 'checke'
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"board": "RO",
"checke": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### fehler-verpflegung-nicht-angeboten
# @status 422
# @feld errorCode = "ERR_BOARD_NOT_OFFERED"
POST {{baseUrl}}/v1/prices
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"boards": ["AI"],
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### hinweise-now-und-waehrung
# @status 200
# @hinweis now: '{{gestern}}' ignoriert
# @hinweis currency: angefragt 'USD'
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "EZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"now": "{{gestern}}",
"currency": "USD",
"occupancy": {"travellers": [{"age": 40}]}
}
### fehler-text-zu-lang
# @status 422
# @feld errorCode = "ERR_VALIDATION"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}
### fehler-verpflegung-preis
# @status 422
# @feld errorCode = "ERR_BOARD_NOT_OFFERED"
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"board": "AI",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
06-fairness.http
# Fairness: Rate-Limit je API-Key (Handbuch Abschnitt 8).
# "@instanz drossel": der Test schickt diese Anfragen an eine zweite Instanz mit
# Rate 0,1/s und Burst 1 (statt 200/s, Burst 400), damit 429 in zwei Anfragen entsteht.
### drossel-erste-anfrage
# @instanz drossel
# @status 200
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "EZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
### drossel-zweite-anfrage
# @instanz drossel
# @status 429
# @feld errorCode = "ERR_RATE_LIMITED"
# @kopf Retry-After = 10
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{apiKey}}
{
"hotel": "TEST-HOTEL-BASE",
"room": "EZ",
"board": "RO",
"checkIn": "{{D0}}",
"checkOut": "{{D2}}",
"occupancy": {"travellers": [{"age": 40}]}
}
07-betrieb.http
# Betrieb: Gesundheit des Knotens (Handbuch Abschnitt 1.8).
### gesundheit
# @status 200
# @feld status = "ok"
GET {{baseUrl}}/v1/health
08-export.http
# EDF-Lieferung: Vollstand, Aenderungen, Quittung (Handbuch Abschnitt 10).
# Die Hauptinstanz laeuft mit dem Voreinstellungs-Takt (full 1/h, changes 1/min je Key):
# darum ruft jedes Beispiel, das den Takt verbraucht, mit einem eigenen Key ab.
### export-voll
# @status 200
# @kopf X-Export-Epoch
# @kopf X-Export-Seq
# @kopf X-Export-From = 0
# @kopf X-Export-More = false
# @feld tenant = "TEST-TENANT-A"
# @feld scope = ""
# @feld type = "full"
# @merke epoch -> exportEpoch
# @merke to_seq -> exportSeq
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{apiKey}}
### export-partner
# @status 200
# @feld tenant = "TEST-TENANT-A"
# @feld scope = "TEST-PARTNER-DISCOUNT"
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{rabattKey}}
### export-nichts-neu
# @status 204
# @kopf X-Export-Seq
# @kopf X-Export-More = false
GET {{baseUrl}}/v1/export/edf/changes?epoch={{exportEpoch}}&since={{exportSeq}}
X-Api-Key: {{apiKey}}
### export-quittung
# @status 204
POST {{baseUrl}}/v1/export/edf/ack
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"epoch": "{{exportEpoch}}", "seq": {{exportSeq}}}
### export-stand-unlesbar
# @status 400
# @feld errorCode = "ERR_EXPORT_BAD_CURSOR"
GET {{baseUrl}}/v1/export/edf/changes?epoch={{exportEpoch}}&since=gestern
X-Api-Key: {{apiKey}}
### export-fremder-stand
# @status 409
# @feld errorCode = "ERR_EXPORT_EPOCH"
GET {{baseUrl}}/v1/export/edf/changes?epoch=01J00000000000000000000000&since=1
X-Api-Key: {{partnerKey}}
### export-zu-oft
# @status 429
# @feld errorCode = "ERR_RATE_LIMITED"
# @kopf Retry-After
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{apiKey}}
### export-ohne-recht
# @status 403
# @feld errorCode = "ERR_EXPORT_NOT_ALLOWED"
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{poolKey}}
09-sandbox.http
# Sandbox: Test-Key und Testbuchungen (Handbuch Abschnitt 11). Laeuft nach 08-export.http.
# testKey ist der Test-Zwilling des Basis-Keys apiKey (Seed TEST-SANDBOX).
### sandbox-preis
# @status 200
# @kopf X-TourAPI-Mode = test
# @feld totalCents = 18000
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{testKey}}
X-TourAPI-Require-Mode: test
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"board": "RO",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]}
}
### sandbox-buchen
# @status 200
# @kopf X-TourAPI-Mode = test
# @feld sandbox = true
# @merke reference -> sandboxRef
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{testKey}}
X-TourAPI-Require-Mode: test
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0001",
"reference": "TEST-4711",
"leadPaxName": "Test Person",
"priceCheck": {
"board": "RO",
"currency": "EUR",
"occupancy": {"travellers": [{"age": 40}, {"age": 38}]},
"expectedCents": 18000,
"tolerancePercent": 0
}
}
### sandbox-buchung-lesen
# @status 200
# @feld sandbox = true
# @feld status = "confirmed"
GET {{baseUrl}}/v1/booking?ref={{sandboxRef}}
X-Api-Key: {{testKey}}
### sandbox-live-key-sieht-testbuchung-nicht
# @status 404
# @kopf X-TourAPI-Mode = live
# @feld errorCode = "ERR_BOOKING_NOT_FOUND"
GET {{baseUrl}}/v1/booking?ref={{sandboxRef}}
X-Api-Key: {{apiKey}}
### sandbox-stornieren
# @status 200
# @feld sandbox = true
# @feld alreadyReleased = false
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{testKey}}
{"idemKey": "BEISPIEL-0001"}
### sandbox-szenario-busy
# @status 503
# @kopf Retry-After = 1
# @feld errorCode = "ERR_BOOKING_BUSY"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{testKey}}
X-TourAPI-Sandbox-Scenario: booking_busy
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0002"
}
### sandbox-szenario-busy-wiederholt
# @status 200
# @feld booked = true
# @feld alreadyBooked = false
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{testKey}}
X-TourAPI-Sandbox-Scenario: booking_busy
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0002"
}
### sandbox-live-key-in-testumgebung
# @status 403
# @feld errorCode = "ERR_MODE_MISMATCH"
POST {{baseUrl}}/v1/book
Content-Type: application/json
X-Api-Key: {{apiKey}}
X-TourAPI-Require-Mode: test
{
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"idemKey": "BEISPIEL-0003"
}
### sandbox-szenario-live-key
# @status 422
# @feld errorCode = "ERR_SCENARIO_NOT_ALLOWED"
GET {{baseUrl}}/v1/destinations
X-Api-Key: {{apiKey}}
X-TourAPI-Sandbox-Scenario: rate_limited
10-inhalte.http
# Abschnitt 12: Hotelinhalte (Content-API).
### inhalt-verzeichnis
# @status 200
# @feld hotels[0].code = "TEST-HOTEL-ALTAKTION"
# @merke feedToken -> feedToken
# @merke nextCursor -> inhaltCursor
GET {{baseUrl}}/v1/content/hotels?pageSize=2
X-Api-Key: {{apiKey}}
### inhalt-verzeichnis-weiter
# @status 200
GET {{baseUrl}}/v1/content/hotels?pageSize=2&cursor={{inhaltCursor}}
X-Api-Key: {{apiKey}}
### inhalt-hotel
# @status 200
# @kopf ETag
# @merke-kopf ETag -> inhaltEtag
# @feld code = "TEST-HOTEL-BASE"
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=de,tr
X-Api-Key: {{apiKey}}
### inhalt-hotel-unveraendert
# @status 304
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=de,tr
X-Api-Key: {{apiKey}}
If-None-Match: {{inhaltEtag}}
### inhalt-hotel-alle-sprachen
# @status 200
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE
X-Api-Key: {{apiKey}}
### inhalt-aenderungen
# @status 200
# @feld more = false
GET {{baseUrl}}/v1/content/changes?since={{feedToken}}
X-Api-Key: {{apiKey}}
### inhalt-katalog
# @status 200
# @kopf ETag
GET {{baseUrl}}/v1/content/catalog?lang=de
X-Api-Key: {{apiKey}}
### inhalt-ohne-recht
# @status 403
GET {{baseUrl}}/v1/content/hotels
X-Api-Key: {{poolKey}}
### inhalt-nicht-im-verzeichnis
# @status 404
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-DISCOUNT
X-Api-Key: {{partnerKey}}
### inhalt-sprache-nicht-angeboten
# @status 422
# @hinweis aktive Inhaltssprachen: de, en, tr (Standard de)
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=fr
X-Api-Key: {{apiKey}}
### inhalt-stand-fremder-key
# @status 422
GET {{baseUrl}}/v1/content/changes?since={{feedToken}}
X-Api-Key: {{partnerKey}}