TourAPI – API El Kitabı v1
Alıcı API'si v1: akış, kurallar, hata kataloğu ve örnekler – her örnek her derlemede test olarak çalışır.
İçindekiler
Çeviri, durum 2026-10-09. Geçerli olan Almanca sürümdür.
- 1. Başlangıç
- 2. Bir entegrasyonun akışı
- 3. Fiyat: /v1/price ve /v1/prices (BA)
- 4. Arama: /v1/search (BA)
- 4a. Açık arama: POST /v1/search/open (BA)
- 4b. Tarih matrisi: POST /v1/search/open/dates (BA)
- 4c. Anahtarın sınırları: GET /v1/limits
- 5. Rezervasyon (B) ve rezervasyon bilgisi
- 6. İptal (S): POST /v1/cancel
- 7. Hata kataloğu
- 8. Adalet: hız sınırı ve arama kapısı
- 9. Idempotency ve eşzamanlılık
- 10. EDF teslimatı (önbellek dışa aktarımı)
- 11. Sandbox: test anahtarları ve test rezervasyonları
- 12. Otel içerikleri: /v1/content/*
- 13. Planlananlar ve sınırlar
- Ek: Bir bakışta sınırlar
Bu dokümantasyon giriş yapmadan okunabilir ve erişim bilgisi içermez. Araçlar ve yapay zeka ajanları için: llms.txt · llms-full.txt · handbuch.tr.md · openapi.yaml
El kitabında ara
Bir seyahat portalını veya bir tur operatörü sistemini TourAPI'ye bağlayan geliştiriciler için.
Durum: 30.09.2026, API sürümü v1; değişiklikler değişiklik günlüğünde yer alır. Makine tarafından okunabilir: openapi.yaml
(OpenAPI 3.1). Yapay zeka ajanları (Claude Code, Codex, Antigravity) için: akış, biçimler ve
yeniden deneme kurallarının özeti portalda /doku/agenten.md altında; giriş yaptıktan sonra kendi
erişiminizle doldurulmuş olarak (“Yapay zeka ajanları” sayfası, AGENTS.md olarak indirme).
Bu el kitabındaki her örnek bir testtir. İstekler
beispiele/ altında (JetBrains ve VS Code REST istemcilerinin formatında) yer alır ve
her derlemede test verileriyle yeni başlatılmış bir TourAPI örneğine karşı çalıştırılır; gösterilen yanıtlar
bu sırada gerçek yanıtlarla karşılaştırılır.
| Kısaltma | Anlamı | Endpoint |
|---|---|---|
| BA | Müsaitlik ve fiyat sorgulama, arama | /v1/search, /v1/price, /v1/prices |
| BA | sabit tarih olmadan açık arama (anahtar başına yetki) | /v1/search/open (Bölüm 4a) |
| BA | bir otelin tarih matrisi (anahtar başına yetki) | /v1/search/open/dates (Bölüm 4b) |
| – | kendi anahtarının geçerli sınırları | /v1/limits (Bölüm 4c) |
| B | rezervasyon yapma | /v1/book |
| – | Rezervasyon bilgisini okuma | /v1/booking |
| S | iptal etme | /v1/cancel |
| – | Düğümün sağlık durumu | /v1/health (Bölüm 1.8) |
| – | EDF teslimatı (önbellek dışa aktarımı) | /v1/export/edf/full, /changes, /ack (Bölüm 10) |
| – | Sandbox: test anahtarları, test rezervasyonları, senaryolar | test anahtarıyla tüm endpoint'ler (Bölüm 11) |
| – | Otel içerikleri (ana veriler, konum, metinler, görseller, olanaklar) | /v1/content/hotels, /changes, /catalog (Bölüm 12) |
Konsol/ajanlar: Alıcı API'sinin parçası değildir (tur operatörü konsolunun POST /changes endpoint'i,
oturum üzerinden giriş, API anahtarı yok; açıklama ve sınırlar işletmeciden talep üzerine).
1. Başlangıç
1.1 Erişim
- Her istek API anahtarını
X-Api-Keyheader'ında taşır. Oturum yoktur, token yoktur. - Anahtarı tur operatörü verir (erişim paketi). Bir anahtar tam olarak bir
tur operatörüne (kiracı) ve isteğe bağlı olarak bir müşteri grubuna aittir. Müşteri grubu
özel fiyatları ve, kontenjan grubu olarak, rezervasyonun yapıldığı kontenjanı belirler. Grubu
olmayan bir anahtar temel sözleşme üzerinde çalışır. Bir müşteri grubunun hangi türde olduğunu
tur operatörü belirler:
- Kontenjan grubu (kontenjanlı satış ortağı): yalnızca kendisine
tahsis yapılmış otelleri görür ve bu tahsise karşı rezervasyon yapar. Diğer oteller bu anahtar için
yoktur (
404 ERR_HOTEL_NOT_FOUND, aramada ve/v1/destinationsiçinde yer almaz). O anda hiç tahsisi yoksa hiçbir otel görmez. - Fiyat grubu: tur operatörünün tüm otellerini görür ve genel stoktan grubu olmayan bir anahtar gibi rezervasyon yapar – yalnızca kendi fiyatıyla.
- Kontenjan grubu (kontenjanlı satış ortağı): yalnızca kendisine
tahsis yapılmış otelleri görür ve bu tahsise karşı rezervasyon yapar. Diğer oteller bu anahtar için
yoktur (
- Bir müşteri grubunun özel fiyatı (tahsisli veya tahsissiz) bir otel için
hesaplanamıyorsa (tur operatöründe hatalı fiyat kampanyası), otel bu grup için
yoktur (
404 ERR_HOTEL_NOT_FOUND, aramadadiagnostics.reasonsiçinde nedenERR_HOTEL_NOT_FOUND,/v1/bookde404ile reddeder) – asla sessizce temel fiyat kullanılmaz. - Kiracı, müşteri grubu ve fiyatlar yalnızca anahtardan gelir, asla bir parametreden gelmez.
Diğer tur operatörlerinin otelleri bu anahtar için yoktur (
404). - Eksik, bilinmeyen veya iptal edilmiş anahtar:
401 ERR_UNAUTHORIZED. Askıya alınmış bir tur operatörünün geçerli anahtarı:403 ERR_TENANT_SUSPENDED. Devre dışı bırakılmış bir müşteri grubunun anahtarı:403 ERR_KEY_GROUP_INACTIVE(asla sessizce temel sözleşme). - Anahtarlar tarayıcı koduna veya loglara konmaz. Anahtarını kaybeden, anahtarı tur operatörüne iptal ettirir – ya da (tur operatörü etkinleştirdiyse) iş ortağı portalında kendisi iptal eder.
- İş ortağı portalındaki anahtarlar: Orada erişiminizin anahtarlarını görür, tur operatörünün
serbest bıraktığı canlı anahtarları teslim alır, canlı anahtarları yeniler ve kendi
anahtarlarınızı iptal edersiniz. Portal ham değeri yalnızca bir kez gösterir. API iptal edilen
bir anahtarı birkaç saniye içinde reddeder (
401). - Yenileme: Yeni canlı anahtar aynı haklara sahiptir (müşteri grubu, dışa aktarma, içerik
yetkisi, arama profili). Önceki anahtar tur operatörünün belirlediği süre boyunca geçerli kalır (varsayılan
24 saat, 1 saat ile 7 gün arası) ve ardından saniyesinde reddedilir (
401 ERR_UNAUTHORIZED). Bu süre içinde tüm sistemleri yeni anahtara geçirin. Yeni anahtarı ancak önceki anahtarın süresi dolduktan sonra yeniden yenileyebilirsiniz – böylece aynı anda en fazla iki anahtar geçerli olur. - Geliştirme için test anahtarları (
tk_test_…) vardır: canlı anahtarla aynı veriler, rezervasyonlar yalnızca sandbox'ta (Bölüm 11). Her yanıt moduX-TourAPI-Modeheader'ında belirtir.
1.2 Temel URL, iletim, sürüm
- Temel URL erişim paketinde yer alır; örneklerde
{{baseUrl}}. - Tüm yollar
/v1ile başlar.v1içinde nelerin değişebileceğini uyumluluk taahhüdü düzenler (Bölüm 1.9). Bilinmeyen yanıt alanlarını lütfen yok sayın. - İstekler: UTF-8 JSON,
Content-Type: application/json, en fazla 1 MiB body.GETolanlar/v1/booking,/v1/destinations,/v1/healthve EDF teslimatıdır (/v1/export/edf/full,/changes), diğerlerinin tümüPOST'tur; yanlış metot:405 ERR_METHOD_NOT_ALLOWED. - Yanıtlardaki zaman damgaları (
bookedAt,updatedAt) UTC olarak RFC 3339 formatındadır, ör.2026-09-26T08:15:03Z. - Sunucu bir bağlantıyı 15 sn okuma veya 15 sn yazma sonrasında keser. İstisna:
EDF teslimatının paketleri (
/v1/export/edf/full,/changes) 10 dakikaya kadar yazabilir (Bölüm 10). - Bilinmeyen bir yol (ör.
/v1/…içinde yazım hatası) JSON gövdesi olmadan404döner (text/plain,errorCodeyok); diğer tüm hatalar 1.6'daki biçimdedir.
1.3 Tarih, konaklama, referans tarihi
- Tarih alanları saat ve saat dilimi olmadan
JJJJ-MM-TTbiçiminde takvim günleridir. - Bir konaklama yarı açıktır:
checkInilk gecedir,checkOutayrılış günüdür.checkIn=2026-10-26,checkOut=2026-10-28iki gecedir. - Referans tarihi, Europe/Berlin saat dilimindeki sunucu tarihidir. Erken rezervasyon ve
dönem kuralları her zaman bununla hesaplanır. İstek alanı
nowartık yalnızca tolere edilir: boş bırakın. Farklı bir tarih gönderilirse, sorgu yine de sunucu tarihiyle hesaplanır ve bunuwarningsiçinde belirtir;/v1/bookfarklı birpriceCheck.nowdeğerini reddeder (ERR_NOW_MISMATCH). - İstek başına sınırlar (her hesaplamadan önce devreye girer):
| Sınır | Değer | Kod (422) |
|---|---|---|
| Konaklama başına gece | 1–30 | ERR_EMPTY_STAY, ERR_STAY_TOO_LONG |
| En erken giriş | bugün (referans tarihi) | ERR_STAY_IN_PAST |
| En geç giriş | referans tarihi + 732 gün | ERR_STAY_TOO_FAR |
| İstek başına yolcu | 1–20 | ERR_NO_TRAVELLERS, ERR_TOO_MANY_TRAVELLERS |
| Yaş | 0–120 | ERR_INVALID_AGE |
1.4 Para
- Tüm tutarlar tam sent cinsindendir (
…Cents, tam sayı). 18000 = 180,00. - Yuvarlama: ticari yuvarlama ile 2 basamağa, yolcu başına bir kez (her
fiyat yanıtında
rounding:{"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"}– otelin EDF'sinin beyan ettiği kuralın aynısı). Bir yolcunun kalemleri tam olarak (yuvarlanmadan) toplanır, yalnızca toplam yuvarlanır: buperTravellerCents[i]değeridir,totalCentsbunların toplamıdır. „89,90 üzerinden −%15“ gibi bir kalem −13,485'tir ve toplama kadar öyle kalır. Kalem başına tam tutarıbreakdown[].amountExactgösterir (Bölüm 3.1). - Para birimi otelin sözleşme para birimidir (
currency, ISO 4217). TourAPI döviz çevirmesi yapmaz. İstektekicurrencybir tercihtir: farklıysa yanıt sözleşme para biriminde,warningsiçinde bir uyarıyla gelir. Sözleşmede para birimi tanımlı değilsecurrencyboş kalır, yine bir uyarıyla – „EUR“ tahmin edilmez. priceCheckile/v1/bookçağrısında ise para birimi çelişkisi bir hatadır (ERR_CURRENCY_NOT_AVAILABLE): ortak birimi olmayan tutarlar karşılaştırılmaz.
1.5 Konaklama düzeni
occupancy.travellers, bir odanın yolcularının listesidir; her yolcu için
giriş günündeki age. name ve type gönderilebilir, ancak fiyata etkisi
yoktur. Çocuk fiyatları, tam ücret ödeyenler ve minimum doluluk sözleşmeden çıkar:
- Birinin çocuk mu yetişkin mi olduğuna sabit bir sınır değil, odanın çocuk yaş aralığı karar verir (ör. 2–11 yaş: 14 yaşındaki biri yetişkin fiyatı öder).
- Bir oda belirli sayıda tam ücret ödeyen isteyebilir (ör. çift kişilik odada 2). Daha az yetişkin seyahat ederse, boş kalan tam ücret yerini bir çocuk doldurur ve tam temel fiyatı öder (pansiyon tipi çocuk tarifesiyle); çocuk indirimleri ancak bunun ötesindeki çocuklar için geçerlidir.
- „1. çocuk / 2. çocuk“ gibi kademeler, çocukları otelin belirlediği sırayla sayar (önce en büyük veya önce en küçük). Aynı sıra, hangi çocuğun boş bir tam ücret yerini dolduracağını da belirler.
- Çocuk yaş aralığından küçük olan bebektir: kişi başı fiyatta temel fiyat olmadan, asla bir tam ücret yerinde değil; pansiyon tipi veya ayrı bir bebek fiyatı yalnızca sözleşme bunları belirtiyorsa. „3 kişiden itibaren“ tekliflerinde bir bebek, yalnızca oda onu doluluğa sayıyorsa sayılır.
- Hiçbir yolcu 0'dan az ödemez. Yüzde indirimleri, yolcunun çocuk veya kişi indiriminden sonra borçlu olduğu tutar üzerinden hesaplanır (ücretsiz bir çocuk ücretsiz kalır, −%50 çocuk fiyatında −%20'lik bir erken rezervasyon indirimi yarısına uygulanır).
1.6 Yanıtlar, hatalar, uyarılar
- Başarı: sonuçla birlikte
200. Hata:4xx/5xxile{"errorCode": "ERR_…", "message": "…", "warnings": ["…"]}errorCodekararlıdır ve programlar için tasarlanmıştır,messageinsanlar için Almanca bir metindir ve değişebilir. Tam liste: Bölüm 7. warnings(isteğe bağlı, başarılı yanıtlarda da): API'nin istekte fark ettiği, ancak reddetmediği şeyler – yok sayılan alanlar, farklı para birimi, yok sayılannow. Lütfen loglayın. Birçok entegrasyon hatası tam olarak orada görünür.- İşlem süresi: Bir uç noktanın her yanıtı – hata yanıtları ve
/v1/healthdahil –Server-Timing: tourapi;dur=<ms>başlığını taşır (W3C Server Timing), örn.tourapi;dur=12.4: isteğin uç noktaya ulaşmasından yanıtın başlamasına kadar geçen milisaniye; istek gövdesinin okunması ile hız sınırı ve arama kapısında bekleme (Bölüm 8) dahil, yanıtın aktarımı hariç. Kendi ölçtüğünüz süreyle arasındaki fark ağ ve aktarımdır. Değer bilgi amaçlıdır, bir taahhüt değildir; ihtiyacınız yoksa başlığı yok sayın. - Bilinmeyen alanlar: Sorgu isteklerinde (
/v1/price,/v1/prices,/v1/search) bilinmeyen bir alan yok sayılır vewarningsiçinde belirtilir.occupancyiçinde ise reddedilir (422 ERR_UNKNOWN_FIELD), çünkü orada bir yazım hatası fiyatı değiştirir./v1/bookve/v1/cancelbilinmeyen her alanı reddeder.
1.7 Örneklerin test dünyası
Örnekler işletmecinin test dünyasına (Golden Seed) karşı çalışır: tur operatörü
TEST-TENANT-A, oteller TEST-HOTEL-…, odalar DZ/EZ, pansiyon tipleri RO/BB/HB. Yer tutucular:
- Yer tutucu
{{baseUrl}}- Anlamı
- Temel URL
- Yer tutucu
{{apiKey}}- Anlamı
- Müşteri grubu olmayan anahtar (temel sözleşme).
- Yer tutucu
{{rabattKey}}- Anlamı
TEST-PARTNER-DISCOUNTmüşteri grubunun anahtarı (TEST-HOTEL-DISCOUNTüzerinde −%20, fiyat grubu)
- Yer tutucu
{{partnerKey}}- Anlamı
TEST-PARTNER-BASEkontenjan grubunun anahtarı
- Yer tutucu
{{poolKey}}- Anlamı
TEST-PARTNER-POOLkontenjan grubunun anahtarı, dışa aktarım yetkisi olmadan
- Yer tutucu
{{gesperrterKey}}- Anlamı
- iptal edilmiş anahtar
- Yer tutucu
{{exportEpoch}},{{exportSeq}}- Anlamı
export-vollörneğinin manifestindekiepochveto_seq
- Yer tutucu
{{ohnePreisRef}},{{zweiteRef}}- Anlamı
- Sırasıyla
buchen-ohne-preispruefungvebuchen-gleiche-kundenreferenzörneklerinden rezervasyon referansları
- Yer tutucu
{{D0}},{{D2}}, …- Anlamı
- Test dünyasının giriş günü D0 artı n gün. D0 = test verilerinin ilk kurulduğu gün + 30 gün. D0 yalnızca test verilerinin sabit bir takvim günüdür, 1.3'teki referans tarihi değildir (o her zaman sunucu tarihidir)
- Yer tutucu
{{heute}},{{gestern}}- Anlamı
- Sunucu tarihi (= referans tarihi), önceki gün
- Yer tutucu
{{buchungsRef}}- Anlamı
buchenörneğinden rezervasyon referansı
- Yer tutucu
{{feedToken}},{{inhaltCursor}}- Anlamı
inhalt-verzeichnisörneğindenfeedTokenvenextCursor
- Yer tutucu
{{inhaltEtag}}- Anlamı
inhalt-hotelörneğindenETag
- Yer tutucu
{{*}}- Anlamı
- (yalnızca yanıtlarda) herhangi bir değer, ör. zaman damgası
Test dünyasının fiyatları (DZ, 2 yetişkin, yalnızca oda): ilk gece 100,00, sonraki her
gece oda başına 80,00; kahvaltı +20,00, yarım pansiyon kişi ve gece başına +35,00.
İstisna TEST-HOTEL-KIND (hedef ACE): kişi ve gece başına fiyat (DZ 89,90 / 79,90),
2 ile 11 yaş arası çocuklar −%15.
1.8 Sağlık: GET /v1/health
Load balancer'lar ve izleme için, anahtarsız. 200 {"status": "ok"} şu anlama gelir: Düğüm
stoku yüklemiştir ve veritabanıyla son eşitlemesi tazedir (varsayılan: 60 sn'den
yeni). Aksi halde status degraded (eşitleme çok eski, reason: "sync_stale") veya
down (stok yüklenmemiş, reason: "view_not_loaded") ile 503, ayrıca metin olarak detail. Yanıt
tur operatörü veya stok verisi içermez. Bir gönderici IP'sinden saniyede 10'dan fazla
çağrı gecikmeli yanıtlanır (en fazla 1 sn, Bölüm 8).
Düğüm bir okuma replikası üzerinden okuyorsa, yanıt ayrıca onun gecikmesini
saniye cinsinden belirtir (replica_lag_s). 5 sn'nin üzerinde durum ok kalır, warnings o zaman
"replica_lag" içerir. 503 degraded, eşitleme yaşı artı gecikme sınırı
aştığında (reason: "replica_lag") veya gecikme ölçülemediğinde gelir
(reason: "replica_lag_unknown").
Her yanıt (503 dahil) ayrıca sürecin çalışma süresini saniye cinsinden
(uptime_s) ve derleme durumunu (version, durumu olmayan bir derlemede boş) belirtir.
Düğüm veritabanını ölçer ölçmez db yer alır: db_latency_ms ile "ok" (bir gidiş-dönüşün
süresi, health çağrısında değil eşitleme döngüsünde ölçülür) veya "error" (son
ölçüm başarısız). "error" tek başına durumu değiştirmez — düğüm yüklenmiş
stokundan yanıt verir; ok durumunda warnings içinde "db_error" yer alır ve
eşitleme gerçekleşmezse, sınırdan sonra 503 degraded (sync_stale) gelir.
warnings içindeki "capacity_overlap" (durum ok kalır) şu anlama gelir: Eşitleme döngüsündeki
stok kontrolü, oda tipi başına çakışan kapasite dönemleri bulmuştur — bir
işletmeci bulgusu (stok, yazma yolu dışından değiştirilmiş), isteğin hatası değil.
### gesundheit
GET {{baseUrl}}/v1/health{
"status": "ok",
"db": "ok",
"db_latency_ms": "{{*}}",
"uptime_s": "{{*}}",
"version": "{{*}}"
}1.9 /v1 için uyumluluk taahhüdü
/v1 içinde API yalnızca eklemeli olarak değişir:
/v1 içinde gelebilir | /v1 içinde asla gelmez (bu /v2 olurdu) |
|---|---|
| yeni isteğe bağlı istek alanları | istekte yeni zorunlu alanlar |
| yeni yanıt alanları | alanları kaldırmak veya yeniden adlandırmak |
| yeni endpoint'ler | bir alanın tipini veya anlamını değiştirmek |
yeni ERR_* kodları, her biri hata kataloğunda belgelenmiş ele alma yöntemiyle | mevcut bir ERR_* kodunun anlamını değiştirmek |
Alıcının bunun için yapması gerekenler:
- Bilinmeyen yanıt alanlarını yok sayın, reddetmeyin.
- Bilinmeyen
ERR_*kodlarını HTTP durumuna göre ele alın (4xx: körü körüne tekrarlamayın,5xx/429: aralıklı tekrarlayın, Bölüm 7). messagevewarningsinsanlar için metinlerdir ve taahhüdün parçası değildir.
/v1 içinde sabit: zaman damgaları UTC olarak RFC 3339'dur (Z), tutarlar tam sent (1.4),
metin uzunlukları yazmadan önce kontrol edilir (alan adıyla 422, asla 500, Ek),
/v1/health anahtar gerektirmez (1.8).
1.10 İş ortağı portalına giriş
Portal (dokümantasyon, kendi erişimleriniz ve anahtarlarınız) API'nin parçası değildir; API yalnızca anahtara ihtiyaç duyar. Portala giriş şöyle işler:
- Portal erişimini tur operatörü oluşturur. Bir kullanıcı adı ve tek kullanımlık şifre (30 gün geçerli) alırsınız.
- İlk giriş: kullanıcı adı ve tek kullanımlık şifre, ardından ikinci faktörü kurun (RFC 6238 uyumlu doğrulayıcı uygulama: QR kodunu tarayın veya anahtarı yazın, altı haneli kodu girin), sonra kendi şifrenizi belirleyin. Geçerli bir tek kullanımlık şifre olmadan ikinci faktör kurulamaz.
- Sonraki her giriş: şifre ve güncel kod. Bir kod yalnızca bir kez geçerlidir.
- Yanlış kodlar: 5 yanlıştan sonra giriş sona erer. 7 gün içinde 10 başarısız deneme erişimi kilitler, doğru kod için de. Kilidi yalnızca tur operatörü açabilir.
- Kilitlendi veya telefon kayboldu: tur operatörüne başvurun. „Kilitlenmeyi kaldır“ erişimi mevcut ikinci faktörle yeniden açar. „2. faktörü sıfırla“ yeni bir tek kullanımlık şifre verir; ardından ikinci faktörü ve şifrenizi yeniden kurarsınız, eski şifre artık geçerli değildir.
- Portal ve tur operatörü konsolu ayrıdır: portal erişim bilgileri konsolda geçerli değildir.
2. Bir entegrasyonun akışı
/v1/destinations
-> /v1/search
-> /v1/price | /v1/prices
-> /v1/book idemKey, priceCheck
-> /v1/booking
-> /v1/cancel idemKey/v1/destinations: anahtarın geçerlidestinationkodları./v1/search: başlangıç fiyatı ve müsaitlik bilgisiyle rezerve edilebilir oteller./v1/price: otel, oda, pansiyon ve kişi dağılımı için fiyat bilgisi (bağlayıcı olan yalnızca/v1/book);/v1/prices: tüm pansiyon tipleri (ve odalar) tek seferde./v1/book:idemKeyvepriceCheck(az önce alınan fiyat) ile rezervasyon yapar./v1/booking: rezervasyonu bizim referansımız veya kendi referansınız üzerinden okur./v1/cancel: aynıidemKeyüzerinden iptal eder.
Bilinmesi gereken kurallar:
- Arama ve fiyat bilgi amaçlıdır, bağlayıcı olan yalnızca
/v1/book'tur. Fiyat ile rezervasyon arasında tur operatörü fiyatları veya kontenjanı değiştirebilir.priceCheckile/v1/bookdeğişmiş bir fiyatı, sessizce yeni fiyattan rezervasyon yapmak yerine reddeder (409 ERR_PRICE_DRIFT). - Her rezervasyonun kendi
idemKeydeğeri vardır (çağıran tarafından verilir, ör. kendi işlem numarası). Aynı anahtarla yapılan tekrarlar asla çift rezervasyon oluşturmaz (Bölüm 9). - Hataları körü körüne tekrarlamayın. Hangi hataların tekrarlanmaya değdiği hata kataloğunda (sütun „Çağıran“) yer alır.
3. Fiyat: /v1/price ve /v1/prices (BA)
3.1 POST /v1/price – tek fiyat
Bir otelin tam olarak bir odasını bir konaklama, bir pansiyon tipi ve bir konaklama düzeni için fiyatlandırır.
- Alan
hotel- Zorunlu
- evet
- Anlamı
- Otel kodu
- Alan
room- Zorunlu
- hayır
- Anlamı
- Oda kodu. Yoksa API, konaklama düzenine izin veren ve pansiyon tipini sunan en uygun fiyatlı müsait odayı alır; hiçbiri müsait değilse bunların en uygun fiyatlısını (o zaman
available=false, 3.3). Sözleşme verileri hesaplama çekirdeği tarafından reddedilen bir oda (7.5, ör.ERR_INVALID_AMOUNT,ERR_NO_SECTION) bu sırada atlanır vewarningsiçinde oda ve kodla belirtilir; hiçbir oda hesaplanamazsa hata 422 olarak gelir.roomile bu odanın hatası her zaman 422 olarak gelir.
- Alan
board- Zorunlu
- evet
- Anlamı
- Pansiyon tipi kodu, tam olarak sözleşmedeki gibi (
RO,rodeğil). Eksikse:ERR_BOARD_MISSING; oda (roomolmadan: hiçbir oda) bunu sunmuyorsa:422 ERR_BOARD_NOT_OFFERED
- Alan
checkIn,checkOut- Zorunlu
- evet
- Anlamı
- Konaklama (Bölüm 1.3)
- Alan
occupancy.travellers[]- Zorunlu
- evet
- Anlamı
ageile yolcular
- Alan
currency- Zorunlu
- hayır
- Anlamı
- Tercih edilen para birimi, yalnızca uyarı (1.4)
- Alan
now- Zorunlu
- hayır
- Anlamı
- tolere edilir, yok sayılır (1.3)
Yanıt:
- Alan
room- Anlamı
- fiyatlandırılan oda (istekte
roomyoksa: en uygun fiyatlı müsait oda);/v1/book'a bu şekilde aktarın
- Alan
currency- Anlamı
- Sözleşme para birimi, boş = sözleşmede tanımlı değil
- Alan
totalCents- Anlamı
- Odanın konaklama için toplam fiyatı
- Alan
rounding- Anlamı
- Yanıtın yuvarlama kuralı (Bölüm 1.4)
- Alan
perTravellerCents[]- Anlamı
- Yolcu başına fiyat, yaşa göre azalan sırada (önce en büyük, aynı yaşta istek sırası): kalemlerinin tam toplamı, bir kez yuvarlanmış. Toplam =
totalCents. Oda fiyatlarında (obje fiyatı) oda kalemlerini ilk yolcu taşır, pansiyon tipi ilgili yolcuda yer alır.
- Alan
breakdown[]- Anlamı
- Tekil kalemler:
chargeType(BaseCharge,PhantomBaseCharge,GuestCharge,BoardCharge,Extra),code,traveller(perTravellerCentsiçindeki indeks),night(0'dan başlayan indeks,-1= konaklama başına),amountExact(ondalık sayı olarak tam tutar, ör."-13.485"),amountCents, ekstralardaapplianceCode, bir ekstra ailesinin ekstralarında (aynıapplianceCodedeğerine sahip birden fazla ekstra) ayrıcavariant(varyant; ekstrayı ancak ikisi birlikte belirtir), ücretsiz gece kalemlerinde ayrıcafreeNight: true(bu gece tamamen veya kısmen bağışlanmıştır, ör. „7=6“: yedinci gece yolcu başına temel fiyatı ve – teklife göre – pansiyon tipini sıfırlayan bir kalem taşır). Sıra: gece, onun içinde yolcu, onun içinde hesaplama adımı (temel fiyat, kişi indirimi/ek ücreti, kendi kişi indirimiyle birlikte pansiyon tipi, ekstralar); konaklama başına kalemler en sonda.
- Alan
separateExtras[]- Anlamı
- yalnızca varsa: ayrı gösterilen ekstralar.
inTotal=true: zorunlu ekstra, toplam fiyata dahil.inTotal=false: isteğe bağlı ekstra, toplam fiyata dahil değil.codeekstrayı belirtir, bir ekstra ailesindevariantile birlikte.amountCentsekstranın tam toplamıdır, bir kez yuvarlanmış;inTotal=truedurumunda kendibreakdownsatırlarının toplamından birkaç sent sapabilir – belirleyici olanbreakdown'dur.
- Alan
availability- Anlamı
configured(kontenjan tanımlı),available(her gece açık),minFree(geceler boyunca en küçük boş sayı, 99'a kadar tam;-1= her gece 99'dan fazla boş veya serbest satış;0= en az bir gece rezervasyona kapalı)
- Alan
warnings[]- Anlamı
- Uyarılar (1.6);
roomolmadan ayrıca sözleşme hatası nedeniyle atlanan her oda için:zimmer 'EZ' ausgelassen: ERR_INVALID_AMOUNT (…)
### preis-einzeln
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}]}
}{
"room": "DZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 18000,
"perTravellerCents": [18000, 0],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "100.00", "amountCents": 10000},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 0, "night": 1, "amountExact": "80.00", "amountCents": 8000}
],
"availability": {"configured": true, "available": true, "minFree": 5}
}room olmadan API en uygun fiyatlı uygun odayı arar – burada bir kişi için EZ;
yanıttaki room onu belirtir.
### preis-guenstigstes-zimmer
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}]}
}{
"room": "EZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 12500,
"perTravellerCents": [12500],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "70.00", "amountCents": 7000},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 0, "night": 1, "amountExact": "55.00", "amountCents": 5500}
],
"availability": {"configured": true, "available": true, "minFree": 5}
}Dolu, kapatılmış, kontenjan tanımlanmamış veya – bir müşteri grubunun anahtarında –
tahsis edilmemiş odaları room olmadan yapılan seçim, daha ucuz olsalar bile atlar: Aşağıdaki otelde EZ'nin (70 EUR) kontenjanı yoktur
ve rezervasyona kapalıdır, API daha pahalı olan, rezerve edilebilir DZ'yi alır.
### preis-guenstigstes-verfuegbares
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}]}
}{
"room": "DZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 10000,
"perTravellerCents": [10000],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "100.00", "amountCents": 10000}
],
"availability": {"configured": true, "available": true, "minFree": 5}
}Oda fiyatlarında kişi başı fiyat. Birçok sözleşme kişiyi değil odayı fiyatlandırır
(obje fiyatı). Bu durumda tüm oda kalemleri – temel fiyat, oda veya işlem başına ekstralar –
perTravellerCents içinde ilk yolcunun kalemine yazılır, diğerleri bunun karşılığında 0 taşır
(preis-einzeln örneğinde: [18000, 0]). Pansiyon tipi, obje fiyatında da her zaman kişi ve gece başına
bir fiyattır: ilgili yolcuda yer alır (kahvaltı ile [22000, 4000],
bkz. preis-alle-verpflegungen); tek başına seyahat eden kişi tam oda fiyatını, ancak yalnızca
bir pansiyon tipini öder. Kişi başına sabit bir indirim (ör. kişi başına −20 € erken rezervasyon) obje
fiyatında oda fiyatını düşürür ve bu nedenle yine ilk kalemde yer alır. Bu kasıtlıdır ve böyle kalır
(EDF 5.1.6: „objektbasierte Zusatzleistungen werden der 1. Person zugerechnet“; her kalem
bir kez yuvarlanır, toplam her zaman tam olarak totalCents olur). İlk kalem en büyük
yolcuya aittir – perTravellerCents ve breakdown[].traveller isteğin sırasına göre değil,
yaşa göre azalan sırada dizilir. Kişiye bağlı kalemler (ör.
çocuk fiyatları) ilgili yolcuda yer alır. Bu nedenle perTravellerCents „kişi başı“
gösterim için tasarlanmamıştır: totalCents değerini yolcu sayısına bölün
ve kendiniz yuvarlayın.
Fiyat anahtara bağlıdır: Aynı istek bir müşteri grubunun anahtarıyla o grubun
özel fiyatını verir (burada −%20). TEST-PARTNER-DISCOUNT bir fiyat grubudur: genel
stoktan rezervasyon yapar, availability grubu olmayan anahtardakiyle aynıdır (1.1).
### preis-kundengruppe
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}]}
}{
"room": "DZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 14400,
"perTravellerCents": [14400, 0],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "80.00", "amountCents": 8000},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 0, "night": 1, "amountExact": "64.00", "amountCents": 6400}
],
"availability": {"configured": true, "available": true, "minFree": 5}
}Çocuk indirimli kişi başı fiyat: 89,90 üzerinden −%15, −13,485 eder – bir sentin
kesri. Kalem tam kalır (amountExact); yalnızca çocuğun toplamı bir kez yuvarlanır:
89,90 − 13,485 + 79,90 − 11,985 = 144,33 → perTravellerCents[2] = 14433. Bir yolcunun amountCents
değerleri, tam olarak onun fiyatını verecek şekilde dağıtılır: her satır, yolcunun o satıra kadarki
yuvarlanmış kümülatif toplamı eksi bir önceki satıra kadarki toplamdır
(8990, −1348, 7990, −1199 = 14433). Kalemleri tek tek yuvarlayıp toplayan (−13,49, −11,99)
144,32'ye ulaşır – bu fiyat değildir.
### preis-kind-bruchcent
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}]}
}{
"room": "DZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 48393,
"perTravellerCents": [16980, 16980, 14433],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "89.90", "amountCents": 8990},
{"chargeType": "BaseCharge", "code": "Base", "traveller": 1, "night": 0, "amountExact": "89.90", "amountCents": 8990},
{"chargeType": "BaseCharge", "code": "Base", "traveller": 2, "night": 0, "amountExact": "89.90", "amountCents": 8990},
{"chargeType": "GuestCharge", "code": "Base", "traveller": 2, "night": 0, "amountExact": "-13.485", "amountCents": -1348},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 0, "night": 1, "amountExact": "79.90", "amountCents": 7990},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 1, "night": 1, "amountExact": "79.90", "amountCents": 7990},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 2, "night": 1, "amountExact": "79.90", "amountCents": 7990},
{"chargeType": "GuestCharge", "code": "ExtraDay", "traveller": 2, "night": 1, "amountExact": "-11.985", "amountCents": -1199}
],
"availability": {"configured": true, "available": true, "minFree": 5}
}Ücretsiz geceler („7=6“). Bir geceyi bağışlayan kalem, teklifin
applianceCode değeri ve freeNight: true ile bir Extra'dır; toplam fiyata dahildir ve
bağışlanan gecede her yolcu için doğrudan onun temel fiyatının arkasında yer alır. Test dünyasında
(TEST-HOTEL-FREINACHT, DZ, yalnızca oda, kişi başı fiyat: ilk gece 100,00, sonraki her gece
80,00, checkIn = {{D0}}) 2 yetişkin 7 gece için 1160,00 yerine 1000,00 öder: gece 6
(yedinci gece) her yolcu için {"chargeType": "Extra", "code": "PN", "night": 6, "amountExact":
"-80.00", "applianceCode": "FSO1", "freeNight": true} taşır. Yarım pansiyonla aynı kalem
pansiyon tipini de bağışlar (-115.00). 14 gece iki ücretsiz gece verir (gece 12 ve 13), 6 gece
hiç vermez.
3.2 POST /v1/prices – tüm pansiyon tipleri tek seferde
/v1/price gibi, ancak board yerine isteğe bağlı boards[] (yoksa: odanın tüm pansiyon
tipleri) ve isteğe bağlı room (yoksa: tüm odalar). Konaklama düzenine izin
vermeyen odalar düşer; hiçbiri izin vermiyorsa neden hata olarak gelir
(ERR_OCCUPANCY_NOT_ALLOWED). Hiçbir odanın sunmadığı, istenen bir pansiyon tipi:
422 ERR_BOARD_NOT_OFFERED. board alanı burada filtreleme yapmaz: Onu gönderen
yine de tüm pansiyon tiplerini ve warnings içinde bir uyarı alır (aşağıdaki örnek);
filtreleme yalnızca boards[] ile yapılır.
Yanıt: currency, rounding, room ve boards[] içeren rooms[] (her pansiyon tipi için board,
globalType (EDF dışa aktarımındaki ve açık aramadaki pansiyon türü: RO için AO, aksi halde tur operatörünün eşlemesi, aksi halde bir pansiyon türüyse kodun kendisi, aksi halde XX = eşlenemez), totalCents, perTravellerCents, separateExtras,
availability), oda başına fiyata göre artan sırada; warnings. breakdown yok.
Bir odanın bir pansiyon tipi bu konaklama düzeni için hesaplanamıyorsa, çünkü sözleşme orada
hatalıdır (ERR_NEGATIVE_TRAVELLER_PRICE, ERR_NEGATIVE_PERCENT_BASE, Bölüm 7.5)
veya bu yolcu grubuna satılmıyordur (ERR_BOARD_NOT_AVAILABLE, 3.5),
yalnızca bu kombinasyon düşer: fiyatsız olarak rooms[].errors[] içinde (board,
globalType, errorCode, message) ve warnings içinde yer alır; matrisin geri kalanı fiyatlanmış kalır,
odanın boards[] listesi o zaman boş olabilir. Bir odanın diğer her sözleşme hatasında da
aynısı geçerlidir (Bölüm 7.5, ör. ERR_NO_SECTION: bir gece için sözleşmede sezon yok):
etkilenen pansiyon tipleri kodla birlikte rooms[].errors[] ve warnings içinde yer alır,
diğer tüm odalar room ve board ile /v1/price ile aynı fiyatlarla fiyatlanmış kalır.
Tek bir kombinasyon bile hesaplanamıyorsa kod hata olarak gelir (422). İsteğin kendisindeki
hatalar isteği yine tamamen reddeder.
Süre sınırı: /v1/prices ve room olmadan /v1/price birden fazla odayı veya
pansiyon tipini hesaplar; bu 2 sn'yi aşarsa (normal işletimde birkaç milisaniye sürer)
503 ERR_PRICE_TIMEOUT gelir – asla yarım bir matris veya odaların bir kısmından seçilmiş
„en uygun fiyatlı“ bir oda gelmez. Çözüm: room veya boards belirtin. Süre sınırı /v1/prices için her zaman geçerlidir,
room ve tek bir pansiyon tipiyle de; yalnızca room ile /v1/price çağrısının kendi
süre sınırı yoktur ve bu nedenle güvenli çıkış yoludur. 503, Retry-After taşımaz: önce daraltın,
sonra tekrarlayın. Çağıran bağlantıyı kapatırsa
hesaplama iptal edilir ve yanıt verilmez.
### preis-alle-verpflegungen
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}]}
}{
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"rooms": [
{
"room": "DZ",
"boards": [
{"board": "RO", "globalType": "AO", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"board": "BB", "globalType": "BB", "totalCents": 26000, "perTravellerCents": [22000, 4000],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"board": "HB", "globalType": "HB", "totalCents": 32000, "perTravellerCents": [25000, 7000],
"availability": {"configured": true, "available": true, "minFree": 5}}
]
}
]
}boards[] yerine board ile, onsuz halle aynı matris gelir, ayrıca şu uyarı
board: 'HB' wird bei /v1/prices ignoriert — Verpflegungen ueber boards waehlen (fehlt boards:
alle des Zimmers):
### preis-alle-verpflegungen-board-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}]}
}3.3 Fiyat yanıtlarında müsaitlik
availability her zaman doludur ve fiyatlandırılan odayı tüm geceler boyunca ifade eder.
available=false olan bir fiyat bir fiyat bilgisidir, teklif değildir: rezervasyon
başarısız olur (Bölüm 5.3). Tam olarak /v1/book'un karşısında satış yaptığı şey sayılır: rezervasyonlar ve
günlük durumdan sonra gece başına boş kapasite ve bir kontenjan grubunun anahtarında
ek olarak onun tahsisi (grubun zaten rezerve ettiği düşülmüştür; oda ve gece için tahsis
yoksa hiçbir şey boş değildir). Bir fiyat grubu, grubu olmayan bir anahtar gibi sayılır (1.1). minFree bunların geceler boyunca en küçüğüdür.
TourAPI gece başına 99'a kadar tam sayar. Hangi gecenin minFree'ye neyle katkıda bulunduğu:
| Gece | minFree'ye katkı | Allotment dosyası (Bölüm 10) |
|---|---|---|
| 1 ile 99 arası birim boş | sayının kendisi | 01–99 |
| 99'dan fazla boş veya serbest satış | minFree'yi düşürmez | ** |
| Satış durdurma | 0 | SS |
| talep üzerine | 0 | RR |
| dolu, kapalı, kapasitesiz, oda ve gece için tahsisi olmayan müşteri grubu | 0 | 00 |
minFree yalnızca her gecede 99'dan fazla boş yer varsa veya serbest satıştaysa -1'dir;
satış durdurma, talep üzerine veya 0 olan tek bir gece minFree'yi 0 yapar (available=false). Bu,
önbellek teslimatının EDF allotment'ındaki gösterimle aynıdır, böylece önbellek ve API
aynı sayıyı gösterir.
configured=true: TourAPI bu oda için bir kontenjan biliyor. Bu henüz her bir gece hakkında bir şey söylemez: Kapasite girilmemiş bir gece odayıavailable=falseyapar (minFree0), ancak odaconfigured=truekalır.configured=false: bu oda için hiç kontenjan tanımlı değildir; rezervasyon yapılamaz.
Yalnızca tek tek gecelerde kapasite eksikse, arama ve /v1/book aynı nedeni belirtir:
ERR_NO_INVENTORY (arama 4.2, rezervasyon 5.3). „Rezerve edilebilir“ için belirleyici olan configured değil,
available'dır.
availability bir anlık durumdur, taahhüt değildir; bağlayıcı kontrolü yalnızca /v1/book yapar. Bir rezervasyonu
veya iptali, onu gerçekleştiren sunucu düğümü bir sonraki istekte gösterir
(minFree düşer veya yükselir). Diğer düğümler, diğer kanalların rezervasyonları ve sözleşme değişiklikleri
birkaç saniye içinde yansır – aynı şekilde kendi düğümü de, yeni durumu hemen yükleyemediği
nadir durumda (rezervasyonun kendisi yine de geçerlidir).
3.4 Odanın satış kuralları: minimum konaklama, giriş günleri, satış penceresi, release
Bir otel sözleşmesi, otelin hangi konaklamaları kabul ettiğini belirleyebilir, örneğin „yüksek sezonda en az 7 gece, giriş yalnızca cumartesi“, „yarım pansiyon yalnızca 31.10.'a kadar girişte“ veya „release 14 gün“ (rezervasyon en geç girişten 15 gün önce). Bu tür kurallar fiyatı değiştirmez; bir odanın istenen konaklama için sunulup sunulmayacağına karar verir. Bir kuralın hariç tuttuğu konaklama fiyat almaz:
| Kod | Kural şunu gerektirir … | Çağıran |
|---|---|---|
ERR_STAY_LENGTH_NOT_ALLOWED | farklı bir konaklama süresi (minimum veya maksimum gece) | süreyi değiştirin |
ERR_ARRIVAL_DAY_NOT_ALLOWED | farklı bir giriş veya çıkış haftanın günü | seyahat günlerini kaydırın |
ERR_TRAVEL_DATES_NOT_ALLOWED | belirli bir dönem içinde seyahat tarihleri (satış penceresi) | farklı dönem |
ERR_BOARD_NOT_ALLOWED | bu konaklama için farklı bir pansiyon tipi | farklı pansiyon tipi |
ERR_LEAD_TIME_NOT_ALLOWED | daha uzun ön süre: giriş release süresi içinde | daha geç giriş |
message odayı, kuralı ve gerekeni belirtir, örneğin „Zimmer DZ, Verkaufsregel 1: wenn
Anreise 2026-07-01 bis 2026-08-31, verlangt mindestens 7 Nächte“. Bir konaklama bir kuralın
birden fazla kısmını ihlal ederse şu sıra geçerlidir: süre, haftanın günü, dönem, pansiyon tipi,
release.
Release (ön süre). n günlük release içeren bir kural, referans tarihi (sunucu tarihi,
1.3) ile giriş arasında n günden fazla takvim günü gerektirir: release 3 ve referans
tarihi 10.05. ise 13.05. girişi hâlâ kapalıdır, 14.05.'ten itibaren rezerve edilebilir; release
0 ise yalnızca referans tarihindeki giriş kapalıdır. Release bir döneme bağlı olabilir (örneğin
„eylülden itibaren 14 gün“): konaklamanın bir gecesi o dönemdeyse geçerlidir, girişe
kadar ölçülür. Kural çıkışa bağlıysa (ApplyTo Departure), süre çıkışa kadar ölçülür:
bu durumda referans tarihi ile çıkış arasında n günden fazla takvim günü gerekir. message referans tarihini, girişi ve ön süreyi belirtir. Bugün kapalı olan bir
konaklama yarın açılmaz; tekrar denemek işe yaramaz.
/v1/price:roomolmadan, kuralı konaklamayı hariç tutan bir oda seçimden düşer; hiçbir oda konaklamayı kabul etmezse neden 422 olarak gelir. Bu neden, başka bir odanınERR_OCCUPANCY_NOT_ALLOWEDhatasına göre önceliklidir, çünkü neyin değiştirilmesi gerektiğini daha kesin söyler./v1/prices: kurallar pansiyon tipi başına geçerli olabilir; yalnızca ilgili pansiyon tipi düşer. Geriye bir şey kalmazsa neden 422 olarak gelir./v1/search: otel düşer, koddiagnostics.reasonsiçinde yer alır./v1/book:priceCheckile kural istenen pansiyon tipi için geçerlidir;priceCheckolmadan (pansiyon tipi bilinmiyor), odanın bir pansiyon tipi konaklamayı kabul eder etmez satış yapılır.
ERR_ROOM_RESTRICTION_INVALID (422) şu anlama gelir: sözleşmedeki bir kural değerlendirilemiyor. Bu
bir sözleşme hatasıdır – bildirin.
3.5 Yalnızca belirli yolcu grupları için pansiyon tipi
Bir pansiyon tipi ek ücreti yolcu grubunun bileşimine bağlı olabilir, örneğin
„yarım pansiyon ek ücreti en az 2 yetişkinli gruplar için geçerlidir“. İstenen
konaklama düzeni buna uymuyorsa, bu pansiyon tipi bu konaklama düzeni için rezerve edilemez:
422 ERR_BOARD_NOT_AVAILABLE. TourAPI hiçbir zaman bir pansiyon tipi için pansiyon tipi olmadan
fiyat hesaplamaz. message pansiyon tipini, yolcuyu, geceyi ve gereken grubu belirtir. Bu
bir sözleşme hatası değildir; farklı bir pansiyon tipi veya konaklama düzeni hesaplanabilir (Çağıran: farklı
pansiyon tipi veya konaklama düzeni).
/v1/price:roomolmadan oda bu pansiyon tipi için seçimden düşer (bir satış kuralında olduğu gibi, 3.4); hiçbir oda hesaplanamazsa neden 422 olarak gelir./v1/prices: odanın yalnızca bu pansiyon tipi düşer,errorCodeilerooms[].errors[]içinde bir kayıt olarak (3.2); geri kalanı fiyatlanmış kalır./v1/search: otel düşer, koddiagnostics.reasonsiçinde yer alır.priceCheckile/v1/book: 422, hiçbir şey rezerve edilmez.
4. Arama: /v1/search (BA)
4.1 İstek ve yanıt
Tur operatörünün bir konaklama, bir pansiyon tipi ve bir konaklama düzeni için rezerve edilebilir
otellerini bulur, her otel için en uygun fiyatlı müsait odayla (room olmadan /v1/price
gibi): Dolu olan daha ucuz bir oda, başka bir oda rezerve edilebilir olduğu sürece
oteli listeden düşürmez.
- Alan
destination- Zorunlu
- hayır
- Anlamı
- Otelin bölge veya havalimanı kodu (aşağıda); boş = tüm oteller
- Alan
board,checkIn,checkOut,occupancy,currency,now- Zorunlu
/v1/pricegibi
- Alan
includeUnavailable- Zorunlu
- hayır
- Anlamı
true: rezerve edilemeyen oteller işaretlenmiş olarak gelir (varsayılanfalse)
- Alan
pageSize,cursor- Zorunlu
- hayır
- Anlamı
- Sayfalar, Bölüm 4.3
Yanıt:
- Alan
results[]- Anlamı
- Sayfanın sonuçları,
fromTotalCents'e göre artan, eşitlikte otel koduna göre
- Alan
results[].hotel,name,room- Anlamı
- Otel ve fiyatın ilişkili olduğu oda
- Alan
results[].fromTotalCents,currency- Anlamı
- Otelin sözleşme para biriminde başlangıç fiyatı (en uygun fiyatlı müsait oda;
bookable=falsedurumunda genel olarak en uygun fiyatlı oda)
- Alan
results[].availability- Anlamı
/v1/price'taki gibi
- Alan
results[].bookable- Anlamı
true= tüm geceler müsait
- Alan
results[].reason,priceInformational- Anlamı
- yalnızca
bookable=falsedurumunda (yalnızcaincludeUnavailableile): neden ve „yalnızca fiyat bilgisi“ işareti
- Alan
diagnostics- Anlamı
- sayfa başına:
considered= kontrol edilen oteller =returned+skipped;reasons[]= otellerin neden düştüğü, her neden için sayıyla;timeBudgetExhausted= sayfa zaman bütçesi nedeniyle kesildi (4.3);roomErrors[]= kontrol edilen otellerin bir sözleşme hatası (7.5) nedeniyle atlanan odaları, her kod için sayıyla – otel başka bir odayla eşleşse bile
- Alan
nextCursor- Anlamı
- kontrol edilecek başka oteller olduğu sürece dolu (4.3)
- Alan
warnings[]- Anlamı
- Uyarılar; karışık sözleşme para birimlerinde toplu bir uyarı
Arama, düşen otellerin otel kodlarını belirtmez, yalnızca nedenleri ve sayıları. Boş
sonuç listesi bu nedenle „stok yok“ anlamına gelmez: diagnostics.reasons ör. sezonun
uymadığını (ERR_NO_SECTION), her şeyin dolu olduğunu (ERR_NOT_AVAILABLE), bir gece için
kontenjan tanımlanmadığını (ERR_NO_INVENTORY) veya otelin hiçbir odasının
istenen pansiyon tipini sunmadığını (ERR_BOARD_NOT_OFFERED) söyler.
destination kodlarının nereden geldiği: Her otelin, tur operatörünün sözleşmesinde
bir bölge kodu (ör. PMI) ve isteğe bağlı havalimanı kodları vardır; destination
bunlardan biriyle tam olarak aynıysa otel eşleşir (büyük/küçük harf önemlidir). Bölge kodları
yalnızca A-Z a-z 0-9 . _ - karakterlerinden oluşur (1 ile 64 karakter, serbest metin yok); havalimanı
kodları üç büyük harfli IATA kodlarıdır. Anahtarın geçerli kodlarını
GET /v1/destinations verir (4.5). Bu anahtar için hiç oteli olmayan bir kod
bir hatadır: 422 ERR_UNKNOWN_DESTINATION (örnek suche-unbekanntes-ziel), asla
sessizce boş bir liste değil. İlk sayfa (cursor olmadan) kontrol edilir; hedef
sayfalama sırasında kaybolursa arama boş bir son sayfayla biter (4.3).
### suche-ziel
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}]}
}{
"results": [
{"hotel": "TEST-HOTEL-BASE", "name": "TEST Basis Palma", "room": "DZ", "currency": "EUR",
"fromTotalCents": 18000, "availability": {"configured": true, "available": true, "minFree": 5},
"bookable": true},
{"hotel": "TEST-HOTEL-DISCOUNT", "name": "TEST Rabatt Palma", "room": "DZ", "currency": "EUR",
"fromTotalCents": 18000, "availability": {"configured": true, "available": true, "minFree": 5},
"bookable": true},
{"hotel": "TEST-HOTEL-TWIN", "name": "TEST Zwilling A Palma", "room": "DZ", "currency": "EUR",
"fromTotalCents": 18000, "availability": {"configured": true, "available": true, "minFree": 5},
"bookable": true}
],
"diagnostics": {"considered": 3, "returned": 3, "skipped": 0}
}Aynı kod küçük harfle yazıldığında API için farklı, bilinmeyen bir hedeftir:
### suche-unbekanntes-ziel
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}]}
}{"errorCode": "ERR_UNKNOWN_DESTINATION",
"message": "destination: kein Hotel mit diesem Ziel-Code fuer diesen Key (gueltige Codes: GET /v1/destinations; Gross-/Kleinschreibung zaehlt)"}4.2 Rezerve edilemeyen oteller
Varsayılan olarak arama yalnızca rezerve edilebilir sonuçları verir ve geri kalanını diagnostics içinde sayar.
includeUnavailable=true ile rezerve edilemeyen oteller bookable=false, reason
ve priceInformational=true ile gelir. Nedenler /v1/book'taki ile aynı anlama gelir:
ERR_NO_INVENTORY: en az bir gece için hiç kontenjan tanımlı değildir – oda için hiç yoktur (configured=false) veya yalnızca bu gece için yoktur./v1/bookaynı konaklamayıERR_NO_INVENTORYile reddeder.ERR_NOT_AVAILABLE: her gecenin kontenjanı vardır, ancak her biri açık değildir (dolu, satış durdurma, kapalı, talep üzerine, müşteri grubunun tahsisi tükenmiş veya mevcut değil). Tam olarak hangi durum olduğunu/v1/bookbelirtir (ERR_SOLD_OUT,ERR_STOP_SALE,ERR_INVENTORY_CLOSED,ERR_GROUP_LIMIT, Bölüm 5.3).
Örnekte TEST-HOTEL-SOLD'un o gece için kapasitesi yoktur, TEST-HOTEL-STOP
satış durdurma durumundadır.
### suche-nicht-buchbare
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}]}
}{
"results": [
{"hotel": "TEST-HOTEL-SOLD", "name": "TEST Ausgebucht Ibiza", "room": "DZ", "currency": "EUR",
"fromTotalCents": 10000, "availability": {"configured": true, "available": false, "minFree": 0},
"bookable": false, "reason": "ERR_NO_INVENTORY", "priceInformational": true},
{"hotel": "TEST-HOTEL-STOP", "name": "TEST Stop-Sale Ibiza", "room": "DZ", "currency": "EUR",
"fromTotalCents": 10000, "availability": {"configured": true, "available": false, "minFree": 0},
"bookable": false, "reason": "ERR_NOT_AVAILABLE", "priceInformational": true}
],
"diagnostics": {"considered": 2, "returned": 2, "skipped": 0}
}4.3 Sayfalar ve cursor
- Bir istek, otel kodu sırasıyla en fazla
pageSizeotelden oluşan bir sayfayı kontrol eder (varsayılan 50, en fazla 100; 1–100 dışında:422 ERR_BAD_PAGE_SIZE). - Başka oteller varsa yanıtta
nextCursoryer alır. Sonraki sayfa: aynı istek artı"cursor": "<nextCursor>". Son sayfadanextCursoryoktur. - Fiyat sıralaması sayfa başına geçerlidir. Fiyata göre tam bir listeye ihtiyaç duyan
sayfaları gezer ve kendisi sıralar.
diagnosticssayfa başına geçerlidir. - Cursor opaktır ve isteğe ve anahtara bağlıdır. Farklı istek (hedef,
dönem, konaklama düzeni, pansiyon tipi,
includeUnavailable) veya farklı anahtar:422 ERR_CURSOR_MISMATCH. Okunamayan veya süresi dolmuş cursor (ör. sunucunun yeniden başlatılmasından sonra):422 ERR_BAD_CURSOR– o zamancursorolmadan yeniden başlayın.pageSizevecurrencysayfalar arasında değişebilir. Cursor'ın uzunluğu sabittir ve otel hakkında hiçbir şey söylemez. - Kesilmiş sayfa: Yük altında bir sayfa 60 ms'den sonra yeni bir otele başlamaz. Bu durumda
pageSize'dan kısadır,diagnostics.timeBudgetExhausted=trueolur venextCursordevam ettirir. Bu bir hata değildir: sayfalamaya devam edin. - Ne
pageSizene decursorgönderilirse ve daha fazla otel varsa, ek olarakwarningsiçinde bir uyarı yer alır – liste o zaman yalnızca ilk sayfadır.
### suche-seitenweise
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}]}
}{
"results": [
{"hotel": "TEST-HOTEL-ALTAKTION", "name": "TEST Altaktion Teneriffa", "room": "DZ", "currency": "EUR",
"fromTotalCents": 18000, "availability": {"configured": true, "available": true, "minFree": 5},
"bookable": true},
{"hotel": "TEST-HOTEL-BASE", "name": "TEST Basis Palma", "room": "DZ", "currency": "EUR",
"fromTotalCents": 18000, "availability": {"configured": true, "available": true, "minFree": 5},
"bookable": true}
],
"diagnostics": {"considered": 3, "returned": 2, "skipped": 1,
"reasons": [{"reason": "ERR_NO_INVENTORY", "count": 1}]},
"nextCursor": "{{*}}"
}4.4 Aramanın yükü ve süre sınırları
Arama en maliyetli istektir. Tur operatörü başına aynı anda en fazla 8 arama çalışır; bunlar
hesaplama süresini paylaşır (tur operatörü başına sunucu çekirdeklerinin dörtte biri), böylece
yoğun bir tur operatörü diğerlerini yavaşlatmaz. Kota doluysa hemen
Retry-After: 1 ile 429 ERR_SEARCH_BUSY gelir. 10 sn'den uzun hesaplama yapan bir arama
503 ERR_SEARCH_TIMEOUT ile iptal edilir – asla sessizce kısaltılmış bir listeyle değil (yük altında
kesilmiş bir sayfada ise her zaman nextCursor vardır, 4.3). Çözüm: destination belirtin veya
daha küçük pageSize. Çağıran bağlantıyı kapatırsa arama hesaplamasını
iptal eder ve artık yanıt vermez.
4.5 GET /v1/destinations – geçerli hedef kodları
Bu anahtarın aramasında destination'ın filtreleyebileceği tüm kodları verir: tur operatörünün
otellerinin bölge ve havalimanı kodları, artan sırada, her kod bir kez. Yalnızca
kendi kodları – bir anahtar asla başka bir tur operatörünün hedeflerini görmez, bir
kontenjan grubunun anahtarı yalnızca tahsisi olan otellerinin hedeflerini (1.1; tahsis yoksa liste
boştur). Parametresizdir; liste, tur operatörü otel eklediğinde veya
kaldırdığında değişir – bir kontenjan grubunun anahtarında ayrıca tur operatörü onun tahsislerini
değiştirdiğinde ve bir müşteri grubunun her anahtarında tur operatörü grubun türünü değiştirdiğinde.
| Alan | Anlamı |
|---|---|
destinations[].code | Kod, destination içine tam olarak böyle aktarılır |
destinations[].name | Gösterim için açık metin; TourAPI kodu tanımıyorsa yoktur |
warnings[] | Uyarılar, ör. gönderilen parametrelerle ilgili (yok sayılırlar) |
### ziele
GET {{baseUrl}}/v1/destinations
X-Api-Key: {{apiKey}}{
"destinations": [
{"code": "ACE", "name": "Lanzarote"},
{"code": "AGP", "name": "Malaga / Costa del Sol"},
{"code": "ALC", "name": "Alicante / Costa Blanca"},
{"code": "BCN", "name": "Barcelona"},
{"code": "FAO", "name": "Faro / Algarve"},
{"code": "FUE", "name": "Fuerteventura"},
{"code": "IBZ", "name": "Ibiza"},
{"code": "LPA", "name": "Gran Canaria"},
{"code": "MAH", "name": "Menorca"},
{"code": "PMI", "name": "Palma de Mallorca"},
{"code": "RHO", "name": "Rhodos"},
{"code": "TFS", "name": "Teneriffa Sued"}
]
}4a. Açık arama: POST /v1/search/open (BA)
4a.1 Ne için
„1 ile 30 Ekim arasında 5 ila 7 gece için en ucuz nerede?“ – otel kodu olmadan ve sabit tarih olmadan. Açık arama her otel için pencerenin tüm varış günleri, aralığın tüm konaklama süreleri, tüm odalar ve pansiyon tipleri üzerinden en iyi teklifi verir ve bunları tüm sayfalar boyunca genel olarak sıralar. İki taahhüt:
- Fiyat kesindir:
best.totalCentsvebest.perTravellerCents, aynı otel, oda, pansiyon tipi, varış ve ayrılış ve aynı konaklama düzeniyle/v1/priceile bit bit aynıdır. Bir önbellekten başlangıç fiyatları yok, örnekleme yok. - Sıralama kanıtlanmıştır: gösterilmeyen hiçbir otelin en iyi teklifi son sonuçtan daha iyi değildir. Yük altında yalnızca sayfa kısalır (4a.4); fiyat asla daha az kesin olmaz, sıralama asla tahmin edilmez.
Bir web sitesinin akışı: açık arama (liste) → tarih matrisi ile bir otelin „tarihler ve
fiyatlar“ı (4b, aynı pencere) → seçilen teklifin /v1/price ile ayrıntısı (best veya
hücre içinden hotel, room, board, checkIn, checkOut, aynı konaklama düzeni:
dökümüyle birlikte aynı fiyat; bu tarihlerin diğer pansiyon tipleri, her pansiyon tipi için
room olmadan /v1/price ile) → priceCheck.expectedCents = gösterilen fiyat ile
/v1/book. Bir teklif token'ı yoktur: rezervasyon fiyatı zaten kontrol eder.
Yetki: Açık arama anahtar başına açılır (yeni anahtarlarda kapalı). Tur operatörü
yöneticisi anahtarda arama profilini belirler (pencere, süreler, hedefler, sayfa boyutu,
zaman bütçesi, istek hızı); en fazla işletmecinin tur operatörüne verdiği kadarı geçerlidir.
Yetki yoksa: 403
ERR_OPEN_SEARCH_NOT_ALLOWED. API profilin sınırlarını alan bazında kontrol eder ve hata
mesajında belirtir (4a.5); GET /v1/limits bunları makine tarafından okunabilir biçimde verir (4c).
4a.2 İstek
- Alan
destinations- Zorunlu
- hayır
- Anlamı
GET /v1/destinations'daki gibi hedef kodları (4.5), birleşim; en fazla profilin izin verdiği kadar
- Alan
hotels- Zorunlu
- hayır
- Anlamı
- Anahtarın otel kodları;
destinationsile birlikte değil. İkisi de yoksa: anahtarın tüm stoku – yalnızca profil tüm hedeflere izin veriyorsa
- Alan
arrivalFrom,arrivalTo- Zorunlu
- evet
- Anlamı
- Varış penceresi, her iki gün dahil;
arrivalFrom≥ referans tarihi,arrivalTo≤ referans tarihi + 732
- Alan
nightsMin,nightsMax- Zorunlu
- evet
- Anlamı
- Konaklama süresi en az–en çok (1–30 ve profil içinde); aradaki her süre sayılır
- Alan
occupancy- Zorunlu
- evet
- Anlamı
- tek oda,
/v1/price'taki gibi
- Alan
boards- Zorunlu
- hayır
- Anlamı
- Pansiyon tipi kodları, tam olarak sözleşmedeki gibi; yoksa = tümü
- Alan
boardTypes- Zorunlu
- hayır
- Anlamı
- EDF dışa aktarımındaki gibi pansiyon türü (
AO,BB,HB,HB+,FB,FB+,SC,AI,AI+,XX);boardsile birlikte: ikisi de uymalı
- Alan
minTotalCents,maxTotalCents- Zorunlu
- hayır
- Anlamı
- Toplam fiyata filtre, sınırlar dahil
- Alan
currency- Zorunlu
- koşullu
- Anlamı
- Sözleşme para birimine filtre, dönüştürme yok. Aramanın otelleri birden fazla para biriminde fiyatlandırıyorsa zorunlu (
422 ERR_CURRENCY_REQUIRED)
- Alan
category- Zorunlu
- hayır
- Anlamı
- resmi kategori (otel ana verilerindeki ulusal sınıflandırma):
schemestarsveyakeys(zorunlu),min/max1 ile 5 arası yarım adımlarla sayı olarak seviye (örn.3.5, eşdeğer3.50), sınırlar dahil (yoksa: 1 veya 5). "4 Superior" 4 sayılır
- Alan
regions- Zorunlu
- hayır
- Anlamı
- otel ana verilerindeki (adres) bölgeler, bunlardan biri; girildiği gibi tam karşılaştırılır (büyük/küçük harf önemlidir); en fazla 50
- Alan
geo- Zorunlu
- hayır
- Anlamı
- yarıçap:
lat,lon(sayı olarak ondalık derece, en fazla 6 ondalık basamak) veradiusKm(0,001 ile 500 arası, en fazla 3 ondalık basamak). Küre üzerinde mesafe (haversine, dünya yarıçapı 6371 km), tam metreye yuvarlanır; sınır içeride sayılır. Tarih çizgisi üzerinden ve kutuplarda doğrudur
- Alan
sort- Zorunlu
- hayır
- Anlamı
price(varsayılan: toplam fiyat),pricePerNight(gece başına fiyat, yuvarlamadan kesir olarak tam karşılaştırılır),hotel(otel kodu)
- Alan
pageSize- Zorunlu
- hayır
- Anlamı
- Sayfa başına sonuç, 1'den profile kadar; belirtilmezse 20 (profil daha azına izin veriyorsa daha az)
- Alan
cursor- Zorunlu
- hayır
- Anlamı
- Önceki sayfanın
nextCursor'ı, değiştirilmeden (4a.4)
Diğer sorgu endpoint'lerinin aksine açık arama her bilinmeyen alanı reddeder
(422 ERR_UNKNOWN_FIELD) – aksi halde bir filtredeki yazım hatası sonuç listesini sessizce
değiştirirdi. now yoktur; sunucunun referans tarihi geçerlidir (1.3).
Otel ana verilerine göre filtreler (category, regions, geo; birlikte VE geçerlidir)
hesaplamadan önce uygulanır: dışarıda kalan bir otel arama kapsamına ait değildir – ne
hotelsInScope içinde sayılır ne de arama profilinin istek başına otel sınırına
(ERR_SEARCH_TOO_BROAD) karşı; böylece tüm stok üzerinde bir yarıçap da mümkündür. Bir
otelde bir filtrenin ihtiyaç duyduğu değer eksikse (resmi kategori, bölge veya koordinat yok)
ve mevcut hiçbir değer onu dışlamıyorsa, arama kapsamında ERR_NO_CATEGORY, ERR_NO_REGION
veya ERR_NO_GEO nedeniyle sayılır (bu sıradaki ilk eksik değer) – otel ana verilerindeki
boşluklar görünür kalır. Değerleri tur operatörü otel ana verilerinde girer (konsol: otel →
İçerik → Ana veri ve konum); bir değişiklik bir sonraki eşitlemeden sonra (saniyeler) geçerli
olur ve stand değişir (4a.4).
4a.3 Yanıt
- Alan
results[].hotel- Anlamı
- Otel kodu;
sortölçütüne göre sıralı, eşitlikte otel koduna göre
- Alan
results[].best- Anlamı
- en iyi teklif:
checkIn,checkOut,nights,room,board,boardType(EDF dışa aktarımındaki gibi pansiyon türü),currency,totalCents,perTravellerCents,availability(/v1/price'taki gibi, her zamanavailable: true)
- Alan
results[].alternatives- Anlamı
- Fiyatsız ön kontrol:
dates= müsaitlik, satış kuralları, sezon ve konaklama düzenine göre en az bir teklifi olan tarihler (varış × süre),boards/boardTypes/roomsbuna göre. Bir üst sınırdır: fiyat hesaplaması bunlardan bazılarını yine de dışlayabilir. Asla fiyat veya sonuç ifadesi olarak okumayın
- Alan
coverage.complete- Anlamı
true: sayfa dolu veya liste bitti.false: zaman bütçesi sayfayı kısalttı (4a.4)
- Alan
coverage.timeBudgetExhausted- Anlamı
- Sayfa zaman bütçesi nedeniyle kısaltıldı (=
complete: false)
- Alan
coverage.standChanged- Anlamı
- veriler önceki sayfadan bu yana değişti (4a.4)
- Alan
coverage.hotelsInScope- Anlamı
- Arama kapsamındaki oteller (hedefler veya
hotels, anahtarın stoku, otel ana verilerine göre filtreler; filtrelenen değeri olmayan oteller de sayılır, 4a.2)
- Alan
coverage.hotelsFeasible- Anlamı
- bunlardan ön kontrole göre en az bir tarihi olanlar – sonuç sayısının üst sınırı („N otele kadar“), sonuç sayısı değil
- Alan
coverage.hotelsPriced- Anlamı
- bu sayfada tam olarak hesaplanan oteller (sunucunun paralel olarak kaç otel hesapladığına da bağlıdır; bu yüzden örneklerde açık bırakılmıştır)
- Alan
coverage.undecided- Anlamı
- Zaman bütçesi bittiğinde yeri henüz belirsiz olan oteller (
completedurumunda 0)
- Alan
coverage.reasons[]- Anlamı
- Tek bir tarihi bile olmayan oteller, neden başına – tüm arama kapsamı için, her sayfada aynı. Hiçbir oda uygun bir pansiyon tipi sunmuyorsa:
ERR_BOARD_NOT_OFFERED./v1/search'te olduğu gibi sonra müsaitlik gelir: hiçbir odanın tek bir boş tarihi bile yoksa neden odur (ERR_NO_INVENTORY,ERR_NOT_AVAILABLE). Aksi halde/v1/price'ın ilk boş tarih için (oda, pansiyon tipi, varış, süre bu sırayla) verdiği yanıt geçerlidir, ör.ERR_OCCUPANCY_NOT_ALLOWED,ERR_NO_SECTION,ERR_STAY_LENGTH_NOT_ALLOWEDveya fiyatı filtrenin dışındaysaERR_OUTSIDE_PRICE_FILTER; ayrıcaERR_CURRENCY_NOT_AVAILABLE(otel başka veya bilinmeyen bir para biriminde fiyatlandırıyor),ERR_HOTEL_NOT_FOUND(müşteri grubu için teklif yok) veERR_NO_CATEGORY,ERR_NO_REGION,ERR_NO_GEO(otelde otel ana verilerine göre bir filtrenin değeri eksik, 4a.2)
- Alan
coverage.priceReasons[]- Anlamı
- Ancak bu sayfadaki tam hesaplamada elenen oteller, neden başına (ör.
ERR_OUTSIDE_PRICE_FILTER)
- Alan
coverage.roomErrors[]- Anlamı
- Sözleşme hatası (7.5) olan odalar, kod başına – asla sessizce atlanmaz
- Alan
stand- Anlamı
- Bu sayfanın veri durumunun tanımlayıcısı (opak)
- Alan
nextCursor- Anlamı
- başka sonuçlar gelebildiği sürece dolu
- Alan
warnings[]- Anlamı
- Uyarılar, ör. veri durumunun değişmesi hakkında
Bir otelin en iyi teklifi: filtrenin tüm tarihler × odalar × pansiyon tipleri üzerinden
ölçütün (toplam fiyat veya gece başına fiyat) minimumu, yalnızca rezerve edilebilir
teklifler. Eşitlikte önce erken varış, sonra kısa süre, sonra sözleşmedeki sırayla oda ve
pansiyon tipi kazanır. sort=hotel ile ölçüt toplam fiyattır.
### suche-offen
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
}{
"results": [
{"hotel": "TEST-HOTEL-BASE",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "room": "DZ", "board": "RO",
"boardType": "AO", "currency": "EUR", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 14, "boards": ["BB", "HB", "RO"], "boardTypes": ["AO", "BB", "HB"], "rooms": 1}},
{"hotel": "TEST-HOTEL-DISCOUNT",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "room": "DZ", "board": "RO",
"boardType": "AO", "currency": "EUR", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 14, "boards": ["BB", "HB", "RO"], "boardTypes": ["AO", "BB", "HB"], "rooms": 1}}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "standChanged": false,
"hotelsInScope": 3, "hotelsFeasible": 3, "hotelsPriced": "{{*}}", "undecided": 0,
"reasons": [], "priceReasons": [], "roomErrors": []},
"stand": "{{*}}",
"nextCursor": "{{*}}"
}Sonraki sayfa, cursor eklenmiş aynı istektir:
### suche-offen-weiter
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}}"
}{
"results": [
{"hotel": "TEST-HOTEL-TWIN",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "room": "DZ", "board": "RO",
"boardType": "AO", "currency": "EUR", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 14, "boards": ["BB", "HB", "RO"], "boardTypes": ["AO", "BB", "HB"], "rooms": 1}}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "standChanged": false,
"hotelsInScope": 3, "hotelsFeasible": 3, "hotelsPriced": "{{*}}", "undecided": 0,
"reasons": [], "priceReasons": [], "roomErrors": []},
"stand": "{{*}}"
}Tüm stok üzerinden, gece başına fiyata göre, yalnızca kahvaltı veya yarım pansiyon.
Pencerede kontenjanı olmayan oteller coverage.reasons içinde neden olarak yer alır:
### suche-offen-je-nacht
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
}{
"results": [
{"hotel": "TEST-HOTEL-ALTAKTION",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D5}}", "nights": 5, "room": "DZ", "board": "BB",
"boardType": "BB", "currency": "EUR", "totalCents": 62000, "perTravellerCents": [52000, 10000],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 42, "boards": ["BB", "HB"], "boardTypes": ["BB", "HB"], "rooms": 1}},
{"hotel": "TEST-HOTEL-BASE",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D5}}", "nights": 5, "room": "DZ", "board": "BB",
"boardType": "BB", "currency": "EUR", "totalCents": 62000, "perTravellerCents": [52000, 10000],
"availability": {"configured": true, "available": true, "minFree": 4}},
"alternatives": {"dates": 42, "boards": ["BB", "HB"], "boardTypes": ["BB", "HB"], "rooms": 1}},
{"hotel": "TEST-HOTEL-DISCOUNT",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D5}}", "nights": 5, "room": "DZ", "board": "BB",
"boardType": "BB", "currency": "EUR", "totalCents": 62000, "perTravellerCents": [52000, 10000],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 42, "boards": ["BB", "HB"], "boardTypes": ["BB", "HB"], "rooms": 1}}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "standChanged": false,
"hotelsInScope": 19, "hotelsFeasible": 13, "hotelsPriced": "{{*}}", "undecided": 0,
"reasons": [{"reason": "ERR_NO_INVENTORY", "count": 6}], "priceReasons": [], "roomErrors": []},
"stand": "{{*}}",
"nextCursor": "{{*}}"
}Palma ve Menorca genelinde otel ana verilerine göre filtrelerle: en az 3,5 yıldız, Mallorca bölgesi, Palma çevresinde 25 km. Alcúdia'daki 3 yıldızlı otel dışarıda kalır, ana verileri girilmemiş Menorca'daki iki otel neden olarak görünür:
### suche-offen-stamm
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}
}{
"results": [
{"hotel": "TEST-HOTEL-BASE",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "room": "DZ", "board": "RO",
"boardType": "AO", "currency": "EUR", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 14, "boards": ["BB", "HB", "RO"], "boardTypes": ["AO", "BB", "HB"], "rooms": 1}},
{"hotel": "TEST-HOTEL-DISCOUNT",
"best": {"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "room": "DZ", "board": "RO",
"boardType": "AO", "currency": "EUR", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
"alternatives": {"dates": 14, "boards": ["BB", "HB", "RO"], "boardTypes": ["AO", "BB", "HB"], "rooms": 1}}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "standChanged": false,
"hotelsInScope": 4, "hotelsFeasible": 2, "hotelsPriced": "{{*}}", "undecided": 0,
"reasons": [{"reason": "ERR_NO_CATEGORY", "count": 2}], "priceReasons": [], "roomErrors": []},
"stand": "{{*}}"
}4a.4 Sayfalar, cursor, veri durumu, zaman bütçesi
- Sayfalar:
nextCursorsonraki sayfaya götürür: aynı istek artı"cursor": "<nextCursor>";pageSizedeğişebilir. Sonraki sayfa son sonucun arkasından devam eder (ölçüt, sonra otel kodu) – tüm sayfalar birlikte tek bir sıralı listedir. Son sayfadanextCursoryoktur; o sayfa boş da olabilir.sort=pricevepricePerNightile sonraki sayfa, önceki sayfaların otellerini yeniden hesaplamaz: listenin derinlerinde de bir sayfa yaklaşık ilk sayfa kadar sürer. - Cursor: opaktır, isteğe ve anahtara bağlıdır, 15 dakika geçerlidir. Farklı
istek (
pageSizedışında herhangi bir alan) veya farklı anahtar:422 ERR_CURSOR_MISMATCH. Okunamayan, süresi dolmuş veya sabit cursor anahtarı olmadan sunucu yeniden başlatıldıktan sonra:422 ERR_BAD_CURSOR– o zamancursorolmadan yeniden başlayın./v1/search'ten gelen bir cursor burada geçerli değildir. - Veri durumu:
stand, tur operatörü sözleşmeleri, promosyonları veya tahsisleri yayınladığında ya da otel ana verilerinde bir otelin bölgesini, koordinatlarını veya resmi kategorisini değiştirdiğinde ve gece yarısı (referans tarihi) değişir; rezervasyonlarda veya diğer içeriklerde (metinler, görseller) değişmez. Veri durumu önceki sayfadan bu yana değiştiyse sonraki sayfa aynı yerden yeni durumda hesaplamaya devam eder;coverage.standChanged: truevewarningsiçinde bir uyarıyla. O zaman (iki sayfa arasındaki başkalarının rezervasyonlarında da olduğu gibi) bir otel iki kez görünebilir veya eksik olabilir:hotel'e göre tekilleştirin. Her sayfanın fiyatları kendi veri durumu için geçerlidir; rezervasyonda fiyatıpriceCheckgüvenceye alır. - Zaman bütçesi: Her sayfanın bir zaman bütçesi vardır (arama profili, ör. 150 ms),
isteğin gelişinden itibaren sayılır. Bütçe tükendiğinde ve sayfada zaten bir sonuç varsa
başka otel hesaplanmaz; yeri zaten kesinleşmiş sonuçlar yine de eklenir. O zaman:
coverage.complete: false,timeBudgetExhausted: true,undecided> 0 ve kalanı içinnextCursor. Gösterilen sonuçlar yine de kesin ve kanıtlanmış sıradadır – sayfalamaya devam edin. Bir sayfa, hâlâ bir sonuç varken asla sonuçsuz bitmez. Kısaltılmış sayfalar bir hata değildir. Özellikle çok büyük aramalarda (en büyük hedefte geniş konaklama süresi aralığına sahip uzun bir varış penceresi), aynı tur operatörünün birden fazla araması aynı anda çalışırken ortaya çıkar. Tam sayfalara ihtiyacınız varsa daha küçük pencereler veya aralıklar sorgulayın ya da aramaları paralel değil art arda yapın. - Yük: Açık arama, tur operatörünün arama yerlerini ve hesaplama süresini
/v1/searchile paylaşır (4.4), ancak arama yerlerinin en fazla yarısını kullanır (8'de 4; tur operatörünün tüm anahtarları ve iki uç nokta birlikte) – geri kalanı/v1/searchiçin boş kalır. Ayrıca anahtar başına arama profilinin istek hızı ve eşzamanlı aramaları geçerlidir (429 ERR_RATE_LIMITEDveyaERR_SEARCH_BUSY,Retry-Afterile);429 ERR_SEARCH_BUSYile reddedilen bir arama istek hızından düşmez. Bir arama 10 sn'den uzun hesaplarsa503 ERR_SEARCH_TIMEOUTile biter, asla kısmi bir sayfayla değil. - Kanıtlanamıyor: Arama bir istek için fiyatı, sıralamayı veya müsaitliği kanıtlayamazsa
(isteğin değil, sunucunun bir hatası), muhtemelen yanlış bir sayfa yerine
500 ERR_INTERNALile yanıt verir.
4a.5 Açık aramanın hataları
Kontroller bu sırayla çalışır; ilk bulgu bildirilir: anahtar → yetki → body ve bilinmeyen alanlar → alan biçimi → API sınırları (1.3) → arama profilinin sınırları → hedefler, oteller, pansiyon tipi, para birimi → cursor → istek hızı ve arama yerleri → hesaplama. Reddedilen bir istek arama yeri işgal etmez ve arama olarak sayılmaz. Kodlar hata kataloğundadır (7.2, 7.3).
### suche-offen-ohne-recht
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}]}
}{"errorCode": "ERR_OPEN_SEARCH_NOT_ALLOWED",
"message": "dieser API-Key hat kein Recht fuer die offene Suche — der Veranstalter-Admin schaltet es frei (Suchprofil des Keys)"}### suche-offen-fenster-zu-breit
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}]}
}{"errorCode": "ERR_WINDOW_TOO_WIDE", "message": "arrivalFrom..arrivalTo: 31 Tage, erlaubt hoechstens 14 (Suchprofil des Keys)"}Müşteri grubunun anahtarı yalnızca bir hedefte arama yapabilir:
### suche-offen-ziel-nicht-erlaubt
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}]}
}{"errorCode": "ERR_DESTINATION_NOT_ALLOWED", "message": "destinations[0]: Ziel ausserhalb der erlaubten Ziele dieses Keys (Suchprofil des Keys)"}Yanlış değerli bir filtre alanı belirtir:
### suche-offen-filter-kaputt
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}
}{"errorCode": "ERR_BAD_FILTER", "message": "geo.radiusKm: 600 ausserhalb 0.001..500"}4b. Tarih matrisi: POST /v1/search/open/dates (BA)
4b.1 Ne için
Bir otelin „tarihler ve fiyatlar“ı: tek bir otel ve açık aramayla aynı pencere için her tarihte (varış × süre) rezerve edilebilir en ucuz teklif ya da neden teklif olmadığı. Yetki ve sınırlar açık aramadaki aynı arama profilinden gelir (4a.1); profilin istek hızı ve eşzamanlı aramaları iki endpoint için birlikte geçerlidir.
- Fiyat kesindir: teklif içeren her hücre, aynı otel, oda, pansiyon tipi, giriş ve çıkış
ve aynı konaklama düzeniyle
/v1/priceile bit düzeyinde aynıdır. - Açık aramayla uyumludur: aynı filtre ve aynı
standile 4a'dakibest, en küçük ölçüte (toplam fiyat veya gecelik fiyat) sahip ilk hücredir – aynı eşitlik kuralı (daha erken varış, daha kısa süre, sözleşme sırasına göre oda ve pansiyon tipi).perBoardilebest, en küçük ölçüte sahip ilk tarihte kendi pansiyon tipinin hücresidir.
4b.2 İstek
- Alan
hotel- Zorunlu
- evet
- Anlamı
- Anahtarın otel kodu (ör. 4a'dan
results[].hotel)
- Alan
arrivalFrom,arrivalTo- Zorunlu
- evet
- Anlamı
- 4a.2'deki gibi varış penceresi; en fazla
matrixMaxWindowDaysgün (arama profili)
- Alan
nightsMin,nightsMax- Zorunlu
- evet
- Anlamı
- 4a.2'deki gibi süre aralığı (profilin izin verdiği süreler)
- Alan
occupancy- Zorunlu
- evet
- Anlamı
- bir oda,
/v1/pricegibi
- Alan
boards,boardTypes- Zorunlu
- hayır
- Anlamı
- 4a.2'deki gibi;
boardsiçindeki her kod otelde sunulmalıdır (422 ERR_BOARD_NOT_OFFERED)
- Alan
rooms- Zorunlu
- hayır
- Anlamı
- Otelin oda kodları; yoksa tümü (bilinmeyen:
404 ERR_ROOM_NOT_FOUND)
- Alan
minTotalCents,maxTotalCents- Zorunlu
- hayır
- Anlamı
- 4a.2'deki gibi toplam fiyat filtresi
- Alan
currency- Zorunlu
- hayır
- Anlamı
- Otelin sözleşme para birimi; otel başka bir para biriminde veya geçerli bir para birimi olmadan fiyatlandırıyorsa:
422 ERR_CURRENCY_NOT_AVAILABLE
- Alan
perBoard- Zorunlu
- hayır
- Anlamı
true: her tarih için pansiyon tipi başına bir hücre (varsayılanfalse: tarih başına bir hücre)
- Alan
category,regions,geo- Zorunlu
- hayır
- Anlamı
- 4a.2'deki gibi otel ana verilerine göre filtreler, aynı etki: otel dışarıda kalırsa arama alanına ait değildir ve matriste hiç hücre yoktur (
cellsboş); değer eksikse her hücreERR_NO_CATEGORY,ERR_NO_REGIONveyaERR_NO_GEOilenoneolur
Hücreler = varış günleri × süreler (perBoard ile × pansiyon tipleri), en fazla
matrixMaxCells (arama profili, aksi halde 422 ERR_SEARCH_TOO_BROAD). Cursor yoktur. Her
bilinmeyen alan: 422 ERR_UNKNOWN_FIELD. Kontrol sırası açık aramanınkidir (4a.5), cursor olmadan.
4b.3 Yanıt
- Alan
hotel,currency- Anlamı
- Otel ve sözleşme para birimi
- Alan
stand- Anlamı
- 4a'daki gibi veri durumu (aynı
stand= aynı veri)
- Alan
boards- Anlamı
- yalnızca
perBoardile: tarih başına pansiyon tipleri sözleşme sırasıyla (odalar üzerinden ilk geçiş, önce RO,/v1/pricesgibi), hücrelerin sırasıyla
- Alan
cells[]- Anlamı
checkIn,nightssırasıyla boşluksuz (perBoardile ardından pansiyon tipi); her hücredecheckIn,checkOut,nights,status. Yalnızca otel, otel ana verilerine göre filtrelerin dışında kalırsa boştur
- Alan
cells[].status = "offer"- Anlamı
- Teklif:
room,board,boardType,totalCents,perTravellerCents,availability(/v1/pricegibi, her zamanavailable: true) – tarihin en ucuz odası/pansiyon tipi, eşitlikte sözleşme sırasına göre
- Alan
cells[].status = "none"- Anlamı
- teklif yok, neden
reasoniçinde: kodlar/v1/priceile aynı, sıra açık aramadaki gibi (4a) – önce müsaitlik (ERR_NO_INVENTORY,ERR_NOT_AVAILABLE), sonra satış kuralları, konaklama düzeni, sezon, fiyat filtresi (ERR_OUTSIDE_PRICE_FILTER) veya bir sözleşme hatası; otel ana verilerine göre filtrelerleERR_NO_CATEGORY,ERR_NO_REGION,ERR_NO_GEO(otelde değer eksik, her hücre)
- Alan
cells[].status = "unchecked"- Anlamı
- zaman bütçesi dolduğu için kontrol edilmedi – asla „teklif yok“ olarak okunmamalı
- Alan
coverage- Anlamı
complete(hiçbir hücreuncheckeddeğil),timeBudgetExhausted,cells=offers+none+unchecked,roomErrors[](kod başına sözleşme hatalı odalar, 7.5)
- Alan
warnings[]- Anlamı
- Uyarılar, ör. kontrol edilmemiş hücreler hakkında
Hücreler matris sırasıyla bloklar halinde hesaplanır; profilin zaman bütçesi dolduğunda kalan
hücreler unchecked kalır (ilk blok her zaman kontrol edilir). O zaman pencereyi veya
süreleri daraltıp yeniden sorun. Matris 10 sn'den uzun hesaplarsa:
503 ERR_SEARCH_TIMEOUT; kanıtlanamazsa: 500 ERR_INTERNAL (4a.4'teki gibi).
### suche-termine
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
}{
"hotel": "TEST-HOTEL-BASE",
"currency": "EUR",
"stand": "{{*}}",
"cells": [
{"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "status": "offer", "room": "DZ", "board": "RO",
"boardType": "AO", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"checkIn": "{{D0}}", "checkOut": "{{D3}}", "nights": 3, "status": "none", "reason": "ERR_OUTSIDE_PRICE_FILTER"},
{"checkIn": "{{D1}}", "checkOut": "{{D3}}", "nights": 2, "status": "offer", "room": "DZ", "board": "RO",
"boardType": "AO", "totalCents": 18000, "perTravellerCents": [18000, 0],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"checkIn": "{{D1}}", "checkOut": "{{D4}}", "nights": 3, "status": "none", "reason": "ERR_OUTSIDE_PRICE_FILTER"}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "cells": 4, "offers": 2, "none": 2, "unchecked": 0,
"roomErrors": []}
}Pansiyon tipi başına, yalnızca kahvaltı ve yarım pansiyon:
### suche-termine-je-verpflegung
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
}{
"hotel": "TEST-HOTEL-BASE",
"currency": "EUR",
"stand": "{{*}}",
"boards": ["BB", "HB"],
"cells": [
{"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "status": "offer", "room": "DZ", "board": "BB",
"boardType": "BB", "totalCents": 26000, "perTravellerCents": [22000, 4000],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"checkIn": "{{D0}}", "checkOut": "{{D2}}", "nights": 2, "status": "offer", "room": "DZ", "board": "HB",
"boardType": "HB", "totalCents": 32000, "perTravellerCents": [25000, 7000],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"checkIn": "{{D0}}", "checkOut": "{{D3}}", "nights": 3, "status": "offer", "room": "DZ", "board": "BB",
"boardType": "BB", "totalCents": 38000, "perTravellerCents": [32000, 6000],
"availability": {"configured": true, "available": true, "minFree": 5}},
{"checkIn": "{{D0}}", "checkOut": "{{D3}}", "nights": 3, "status": "offer", "room": "DZ", "board": "HB",
"boardType": "HB", "totalCents": 47000, "perTravellerCents": [36500, 10500],
"availability": {"configured": true, "available": true, "minFree": 5}}
],
"coverage": {"complete": true, "timeBudgetExhausted": false, "cells": 4, "offers": 4, "none": 0, "unchecked": 0,
"roomErrors": []}
}31 varış günü × 14 süre × 3 pansiyon tipi, profilin izin verdiğinden fazla hücredir:
### suche-termine-zu-viele-zellen
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
}{"errorCode": "ERR_SEARCH_TOO_BROAD",
"message": "Termin-Matrix: 1302 Zellen (Anreisen x Dauern x 3 Verpflegungen), erlaubt hoechstens 500 (Suchprofil des Keys)"}4c. Anahtarın sınırları: GET /v1/limits
Kendi anahtarının geçerli sınırları; böylece bir web sitesi sınırları 422 ile
yoklamak yerine tarih seçimini, süre seçimini ve hedefleri ayarlar. Parametre yok (herhangi
biri: 422
ERR_UNKNOWN_FIELD), arama olarak sayılmaz.
- Alan
rate- Anlamı
- Anahtarın tüm isteklerinin hızı (4.4):
perSecond,burst,scope(key= anahtar ve düğüm başına;testCircle= test anahtarlarının ortak havuzu, 11)
- Alan
export.allowed- Anlamı
- EDF teslimatı yetkisi (10)
- Alan
content.allowed- Anlamı
- İçerik API'sine (
/v1/content/*) erişim: işletmeci tur operatörü için içerikleri açmış ve anahtar içerik yetkisine sahip – oradakiyle aynı kural; erişim yoksa403 ERR_CONTENT_NOT_ALLOWED
- Alan
openSearch.allowed- Anlamı
- Açık arama ve tarih matrisi yetkisi; yetki yoksa yalnızca bu alan bulunur
- Alan
openSearch.maxWindowDays,nightsMin,nightsMax,maxNightsSpan- Anlamı
- Varış penceresi, izin verilen süreler ve istek başına süre aralığı (4a)
- Alan
openSearch.maxDestinations,maxHotels,maxCandidates,maxPageSize- Anlamı
- İstek başına hedefler ve oteller, arama kapsamındaki oteller, sayfa başına sonuçlar (4a)
- Alan
openSearch.timeBudgetMs,rate,burst,concurrency- Anlamı
- Sayfa veya matris başına zaman bütçesi, istek hızı ve eşzamanlı aramalar (iki endpoint birlikte)
- Alan
openSearch.matrixMaxWindowDays,matrixMaxCells- Anlamı
- Tarih matrisinin penceresi ve hücreleri (4b)
- Alan
openSearch.allDestinations,destinations- Anlamı
- tüm hedeflere izin var, aksi halde izin verilen hedef kodları – yalnızca anahtarın envanterinde oteli olanlar (
GET /v1/destinationsgibi)
Değerler tam olarak /v1/search/open ve /v1/search/open/dates uç noktalarının uyguladığı
değerlerdir: işletmecinin tur operatörüne verdiği ile anahtarın profilinin en küçüğü. Bir
sınırı hangi seviyenin belirlediği yanıtta yer almaz. Profildeki değişiklikler birkaç
saniye sonra etkili olur.
### grenzen
GET {{baseUrl}}/v1/limits
X-Api-Key: {{apiKey}}{
"rate": {"perSecond": 200, "burst": 400, "scope": "key"},
"export": {"allowed": true},
"content": {"allowed": true},
"openSearch": {"allowed": true, "maxWindowDays": 14, "nightsMin": 1, "nightsMax": 14, "maxNightsSpan": 3,
"maxDestinations": 3, "maxHotels": 20, "maxCandidates": 500, "maxPageSize": 20,
"timeBudgetMs": 150, "rate": 5, "burst": 20, "concurrency": 1,
"matrixMaxWindowDays": 31, "matrixMaxCells": 500, "allDestinations": true}
}Açık arama yetkisi olmayan bir anahtar:
### grenzen-ohne-recht
GET {{baseUrl}}/v1/limits
X-Api-Key: {{poolKey}}{
"rate": {"perSecond": 200, "burst": 400, "scope": "key"},
"export": {"allowed": false},
"content": {"allowed": false},
"openSearch": {"allowed": false}
}5. Rezervasyon (B) ve rezervasyon bilgisi
5.1 POST /v1/book
- Alan
hotel,room- Zorunlu
- evet
- Anlamı
- Otel ve oda kodu (rezervasyon pansiyon tipinden bağımsızdır; pansiyon tipi
priceCheckiçinde yer alır).roomeksikse:400 ERR_INVALID_BUCKET,priceCheckile ve olmadan
- Alan
checkIn,checkOut- Zorunlu
- evet
- Anlamı
- Konaklama (Bölüm 1.3)
- Alan
quantity- Zorunlu
- evet
- Anlamı
- Oda sayısı, 1–1.000.000 (
400 ERR_QUANTITY_INVALID)
- Alan
idemKey- Zorunlu
- evet
- Anlamı
- işlemin kendi benzersiz anahtarı (Bölüm 9), en fazla 128 karakter; eksikse:
400 ERR_INVALID_IDEM_KEY
- Alan
reference- Zorunlu
- hayır
- Anlamı
- kendi rezervasyon referansı, en fazla 128 karakter; rezervasyon daha sonra bununla okunabilir
- Alan
leadPaxName- Zorunlu
- hayır
- Anlamı
- Ana yolcunun adı, en fazla 255 karakter
- Alan
metadata- Zorunlu
- hayır
- Anlamı
- serbest JSON nesnesi, saklanır ve
/v1/booking'de geri döndürülür, değerlendirilmez.metadata.correlationId(64 karaktere kadar) korelasyon kimliği olarak devralınır.
- Alan
priceCheck- Zorunlu
- hayır, önerilir
- Anlamı
- Satıştan önce fiyat kontrolü, aşağıya bakın
Çok uzun metinleri (idemKey, reference, leadPaxName, metadata.correlationId) API
her satıştan önce 422 ERR_VALIDATION ile reddeder; message alanı, uzunluğu ve sınırı belirtir. Asla
kısaltılmaz.
priceCheck: board, occupancy.travellers[], expectedCents (müşterinin gördüğü
fiyat), tolerancePercent (% olarak izin verilen sapma, ≥ 0), isteğe bağlı currency ve
now. TourAPI fiyatı /v1/price gibi yeniden hesaplar; tolerans değerinden fazla saparsa:
message içinde güncel fiyatla 409 ERR_PRICE_DRIFT, hiçbir şey rezerve edilmez. priceCheck
ile TourAPI kontrol edilen fiyatı rezervasyonda saklar (/v1/booking içinde totalCents, currency,
board). priceCheck olmadan rezervasyon, fiyatsız saf bir kontenjan satışıdır
(totalCents: null). Bu durumda da /v1/book yalnızca /v1/price'ın bu
anahtar için tanıdığı otelleri satar: Geçerli sözleşme olmadan otel yoktur (404 ERR_HOTEL_NOT_FOUND),
kontenjan tanımlı olsa bile.
Yanıt: booked, alreadyBooked (true = tekrar, yeni bir şey satılmadı), reference
(bizim rezervasyon referansımız TA-…), correlationId. correlationId, gönderilen
metadata.correlationId'dir; yoksa TourAPI bir UUID atar ve bunu kayıtta saklar.
Bir tekrar (alreadyBooked=true) her zaman ilk çağrının saklanan correlationId değerini
belirtir – tekrar hiç göndermese veya farklı bir tane gönderse bile.
### buchen
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
}
}{"booked": true, "alreadyBooked": false, "reference": "{{buchungsRef}}", "correlationId": "kette-0815"}5.2 Tekrarlamak güvenlidir
Aynı isteği aynı idemKey ile bir kez daha göndermek – örneğin bir ağ hatasından sonra – yeniden
satış yapmaz, mevcut rezervasyonu onaylar (alreadyBooked: true, aynı
referans).
### buchen-wiederholt
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
}
}{"booked": true, "alreadyBooked": true, "reference": "{{buchungsRef}}", "correlationId": "kette-0815"}Farklı rezervasyon verileriyle (otel, oda, konaklama, miktar) aynı idemKey
çağıranın hatasıdır:
### buchen-anderer-vorgang
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"
}{"errorCode": "ERR_IDEMPOTENCY_MISMATCH", "message": "idemKey bereits mit anderen Buchungsdaten (hotel, room, checkIn, checkOut, quantity) vergeben"}5.3 Bir rezervasyon neden başarısız olur
Satış bir gecede başarısız olursa message etkilenen ilk geceyi belirtir. Hiçbir şey
rezerve edilmez (ya tüm geceler ya hiçbiri).
- Kod
ERR_SOLD_OUT- Durum
- 422
- Anlamı
- Gece dolu
- Kod
ERR_STOP_SALE- Durum
- 422
- Anlamı
- Tur operatörü satışı durdurmuş
- Kod
ERR_INVENTORY_CLOSED- Durum
- 422
- Anlamı
- Gece kapalı veya yalnızca talep üzerine
- Kod
ERR_NO_INVENTORY- Durum
- 422
- Anlamı
- bir gece için kapasite tanımlı değil
- Kod
ERR_GROUP_LIMIT- Durum
- 422
- Anlamı
- müşteri grubunun tahsisi tükenmiş (veya oda ve gece için mevcut değil)
- Kod
ERR_HOTEL_NOT_FOUND- Durum
- 404
- Anlamı
- Otel bu anahtar için yok (ayrıca: geçerli sözleşme yok,
priceCheckile ve olmadan; teklifi olmayan müşteri grubu, 1.1)
- Kod
ERR_PRICE_DRIFT- Durum
- 409
- Anlamı
- Fiyat
priceCheck'ten sapıyor
- Kod
ERR_STAY_LENGTH_NOT_ALLOWED,ERR_ARRIVAL_DAY_NOT_ALLOWED,ERR_TRAVEL_DATES_NOT_ALLOWED,ERR_BOARD_NOT_ALLOWED,ERR_LEAD_TIME_NOT_ALLOWED- Durum
- 422
- Anlamı
- odanın bir satış kuralı konaklamayı hariç tutuyor (3.4); hiçbir şey rezerve edilmez
- Kod
ERR_BOARD_NOT_AVAILABLE- Durum
- 422
- Anlamı
priceCheck'teki pansiyon tipi bu yolcu grubuna satılmıyor (3.5); hiçbir şey rezerve edilmez
### buchen-preis-geaendert
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
}
}{"errorCode": "ERR_PRICE_DRIFT", "message": "Preis hat sich geaendert: aktuell 18000 Cent, erwartet 17000 Cent"}### buchen-ausgebucht
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"
}{"errorCode": "ERR_SOLD_OUT", "message": "Nacht {{D13}} ausgebucht"}### buchen-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"
}{"errorCode": "ERR_STOP_SALE", "message": "Nacht {{D11}} stop-sale"}Tahsisli müşteri grubuna sahip bir anahtar, serbest satıştaki gecelerde de kendi grubunun
tahsisine karşı rezervasyon yapar. Burada TEST-PARTNER-BASE'e o gece için 5 tahsis edilmiştir:
### buchen-zuteilung-erschoepft
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"
}{"errorCode": "ERR_GROUP_LIMIT", "message": "Gruppen-Kontingent fuer {{D20}} erschoepft"}Bir fiyat grubu, grubu olmayan bir anahtar gibi genel stoktan rezervasyon yapar:
### buchen-preisgruppe
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"
}{"booked": true, "alreadyBooked": false, "reference": "{{*}}", "correlationId": "{{*}}"}5.4 GET /v1/booking?ref=… – rezervasyon bilgisi
ref bizim referansımız (TA-…) veya rezervasyondaki kendi reference değerinizdir; bizim
referansımız önceliklidir. Kendi reference değeriniz birden fazla görünür rezervasyonla eşleşirse (iptal edilmişler
dahil): 409 ERR_REFERENCE_AMBIGUOUS, message eşleşen TA-… referanslarını belirtir
(önce en yeni, en fazla 10) – o zaman rezervasyon yanıtındaki bizim referansımızla okuyun. Yanıt:
reference, customerReference, hotel, room, group (yalnızca müşteri grubu rezervasyonlarında; grup
kodu A-Z a-z 0-9 . _ - karakterlerinden, 1 ile 64 karakter),
checkIn, checkOut, quantity, status (confirmed | released), bookedAt,
updatedAt (son değişiklik, iptalde iptal zamanı; ikisi de UTC olarak RFC 3339, ör.
2026-09-26T08:15:03Z), metadata, totalCents, currency, board. Yolcuların kişisel
verilerini API döndürmez.
| Rezervasyon … | rezervasyon bilgisinde |
|---|---|
priceCheck ile | totalCents = kontrol edilen fiyat, currency = sözleşme para birimi, board = priceCheck'teki pansiyon tipi |
priceCheck olmadan | totalCents: null, currency: "", board: "" (boş metinler, fiyat kaydedilmedi) |
reference olmadan | customerReference yok |
metadata olmadan | metadata yok |
| müşteri grubu olmayan anahtarla | group yok |
Görünürlük: Müşteri grubuna sahip bir anahtar yalnızca kendi grubunun rezervasyonlarını görür. Temel
sözleşmedeki bir anahtar tur operatörünün tüm rezervasyonlarını görür, müşteri gruplarınınkiler dahil – ancak
yalnızca kendi rezervasyonlarını iptal edebilir (Bölüm 6). Bilinmeyen veya görünür değil:
404 ERR_BOOKING_NOT_FOUND.
### buchung-lesen
GET {{baseUrl}}/v1/booking?ref={{buchungsRef}}
X-Api-Key: {{apiKey}}{
"reference": "{{buchungsRef}}",
"customerReference": "KUNDE-4711",
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"status": "confirmed",
"bookedAt": "{{*}}",
"updatedAt": "{{*}}",
"metadata": {"correlationId": "kette-0815", "vermittler": "Filiale 12"},
"totalCents": 18000,
"currency": "EUR",
"board": "RO"
}Kendi referansınız üzerinden:
### buchung-lesen-kundenreferenz
GET {{baseUrl}}/v1/booking?ref=KUNDE-4711
X-Api-Key: {{apiKey}}{
"reference": "{{buchungsRef}}",
"customerReference": "KUNDE-4711",
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"status": "confirmed",
"bookedAt": "{{*}}",
"updatedAt": "{{*}}",
"metadata": {"correlationId": "kette-0815", "vermittler": "Filiale 12"},
"totalCents": 18000,
"currency": "EUR",
"board": "RO"
}priceCheck, reference ve metadata olmayan bir rezervasyon – yanıt sunucu tarafından
atanmış bir correlationId taşır, rezervasyon bilgisinde fiyat yoktur:
### buchen-ohne-preispruefung
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"
}{"booked": true, "alreadyBooked": false, "reference": "{{ohnePreisRef}}", "correlationId": "{{*}}"}### buchung-lesen-ohne-preispruefung
GET {{baseUrl}}/v1/booking?ref={{ohnePreisRef}}
X-Api-Key: {{apiKey}}{
"reference": "{{ohnePreisRef}}",
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D20}}",
"checkOut": "{{D21}}",
"quantity": 1,
"status": "confirmed",
"bookedAt": "{{*}}",
"updatedAt": "{{*}}",
"totalCents": null,
"currency": "",
"board": ""
}Aynı kendi referansının ikinci bir rezervasyonda kullanılması onu belirsiz yapar:
### buchen-gleiche-kundenreferenz
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"
}{"booked": true, "alreadyBooked": false, "reference": "{{zweiteRef}}", "correlationId": "{{*}}"}### buchung-lesen-mehrdeutig
GET {{baseUrl}}/v1/booking?ref=KUNDE-4711
X-Api-Key: {{apiKey}}{"errorCode": "ERR_REFERENCE_AMBIGUOUS", "message": "ref 'KUNDE-4711' passt zu mehreren Buchungen ({{zweiteRef}}, {{buchungsRef}}) — mit der TourAPI-Referenz (TA-…) lesen"}6. İptal (S): POST /v1/cancel
Tek alan: rezervasyonun idemKey değeri (eksikse: 400 ERR_INVALID_IDEM_KEY; başka her
alan: 422 ERR_UNKNOWN_FIELD). Tüm gecelerin kontenjanı iade edilir,
durum released olur. Yalnızca aynı anahtar çevresiyle rezerve edilmiş olan iptal
edilebilir: Müşteri grubuna sahip bir anahtar kendi grubunun rezervasyonlarını, temel
sözleşmedeki bir anahtar temel sözleşmenin rezervasyonlarını iptal eder. Diğer her şey 404 ERR_BOOKING_NOT_FOUND'dur.
İptal ücretlerini API hesaplamaz.
Her iptal tur operatöründe zaman ve iptal eden anahtarın kimliğiyle (key_id)
kaydedilir ve onun rezervasyon görünümünde gösterilir; bir
tekrar (alreadyReleased) ikinci bir kayıt oluşturmaz.
Yanıt: released (true), alreadyReleased (true = zaten iptal edilmişti).
### stornieren
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "BEISPIEL-0001"}{"released": true, "alreadyReleased": false}Tekrarlamak güvenlidir:
### stornieren-wiederholt
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "BEISPIEL-0001"}{"released": true, "alreadyReleased": true}Rezervasyon status: released ile okunabilir kalır:
### buchung-lesen-storniert
GET {{baseUrl}}/v1/booking?ref={{buchungsRef}}
X-Api-Key: {{apiKey}}{
"reference": "{{buchungsRef}}",
"customerReference": "KUNDE-4711",
"hotel": "TEST-HOTEL-BASE",
"room": "DZ",
"checkIn": "{{D2}}",
"checkOut": "{{D4}}",
"quantity": 1,
"status": "released",
"bookedAt": "{{*}}",
"updatedAt": "{{*}}",
"metadata": {"correlationId": "kette-0815", "vermittler": "Filiale 12"},
"totalCents": 18000,
"currency": "EUR",
"board": "RO"
}İptal edilmiş bir idemKey tüketilmiştir. Yeni bir rezervasyon için yeni bir anahtar kullanın:
### buchen-nach-storno
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"
}{"errorCode": "ERR_IDEM_KEY_RELEASED", "message": "idemKey gehoert zu einer stornierten Buchung — fuer einen neuen Verkauf einen neuen idemKey verwenden"}### stornieren-unbekannt
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"idemKey": "GIBT-ES-NICHT"}{"errorCode": "ERR_BOOKING_NOT_FOUND", "message": "keine Buchung mit diesem idemKey"}7. Hata kataloğu
Sütun „Çağıran“: İsteği düzeltin = tekrarlamayın, hata istektedir.
Tekrarlayın = aynı isteği daha sonra bir kez daha gönderin (Retry-After varsa en erken
o kadar saniye sonra). Bildirin = tur operatörüne/işletmeciye bildirin, tekrarlamak işe
yaramaz. Bir kod birden fazla endpoint'te görülebilir; durum ve anlam aynı kalır.
7.1 Erişim ve iletim
- Kod
ERR_UNAUTHORIZED- Durum
- 401
- Anlamı
- Anahtar eksik, bilinmiyor veya iptal edilmiş
- Çağıran
- Anahtarı kontrol edin, tekrarlamayın (tekrarlar geciktirilir, Bölüm 8)
- Kod
ERR_TENANT_SUSPENDED- Durum
- 403
- Anlamı
- Anahtar geçerli, tur operatörü askıya alınmış
- Çağıran
- Tur operatörüne sorun, tekrarlamayın
- Kod
ERR_KEY_GROUP_INACTIVE- Durum
- 403
- Anlamı
- Anahtarın müşteri grubu devre dışı
- Çağıran
- Tur operatörüne sorun
- Kod
ERR_MODE_MISMATCH- Durum
- 403
- Anlamı
X-TourAPI-Require-Modeanahtarınkinden farklı bir mod istiyor (ör. test ortamında canlı anahtar); hiçbir şey yürütülmedi (Bölüm 11.1)- Çağıran
- Anahtarı değiştirin, tekrarlamayın
- Kod
ERR_SCENARIO_NOT_ALLOWED- Durum
- 422
- Anlamı
- Canlı anahtarla, bilinmeyen bir senaryoyla veya etkisiz olduğu bir endpoint'te
X-TourAPI-Sandbox-Scenario(Bölüm 11.3) - Çağıran
- İsteği düzeltin
- Kod
ERR_METHOD_NOT_ALLOWED- Durum
- 405
- Anlamı
- yanlış HTTP metodu
- Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_REQUEST- Durum
- 400
- Anlamı
- Body JSON değil, çok büyük (> 1 MiB),
refeksik,priceCheck.tolerancePercentnegatif,priceCheck.currency3 karakterden uzun (daha kısa veya bilinmeyen:422 ERR_CURRENCY_NOT_AVAILABLE); Content API:sinceeksik, parametre birden fazla,lang5'ten fazla veya yinelenen dil içeriyor - Çağıran
- İsteği düzeltin
- Kod
ERR_UNKNOWN_FIELD- Durum
- 422
- Anlamı
occupancyiçinde (sorgu) veya herhangi bir yerde (/v1/search/open,/v1/search/open/dates,/v1/book,/v1/cancel,/v1/export/edf/ackbody'si) bilinmeyen alan;/v1/export/edf/*ve/v1/limitsüzerinde bilinmeyen query parametresi- Çağıran
- İsteği düzeltin
- Kod
ERR_OPEN_SEARCH_NOT_ALLOWED- Durum
- 403
- Anlamı
- anahtarın açık arama ve tarih matrisi yetkisi yok (4a.1; yeni anahtarlarda kapalı;
GET /v1/limitsgösterir) - Çağıran
- Tur operatörüne sorun
- Kod
ERR_DESTINATION_NOT_ALLOWED- Durum
- 403
- Anlamı
- açık arama: hedef (
destinations[i]) veya otel (hotels[i], tarih matrisi:hotel) arama profilinin izin verilen hedeflerinin dışında - Çağıran
- Hedefi arama profilinden alın (
GET /v1/limits)
### fehler-ohne-key
POST {{baseUrl}}/v1/price
Content-Type: application/json
{}{"errorCode": "ERR_UNAUTHORIZED", "message": "fehlender/ungueltiger API-Key"}### fehler-key-widerrufen
POST {{baseUrl}}/v1/price
Content-Type: application/json
X-Api-Key: {{gesperrterKey}}
{}{"errorCode": "ERR_UNAUTHORIZED", "message": "fehlender/ungueltiger API-Key"}### fehler-methode
GET {{baseUrl}}/v1/price
X-Api-Key: {{apiKey}}{"errorCode": "ERR_METHOD_NOT_ALLOWED", "message": "nur POST"}### fehler-tippfehler-belegung
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}]}
}{"errorCode": "ERR_UNKNOWN_FIELD", "message": "unbekanntes Feld 'occupancy.travellers[1].alter' — abgelehnt (die Belegung bestimmt den Preis, hier wird nicht geraten)"}7.2 İstek (alanlar ve sınırlar)
- Kod
ERR_BAD_DATE- Durum
- 422
- Anlamı
- Tarih eksik veya
JJJJ-MM-TTbiçiminde değil (messagealanı belirtir) - Çağıran
- İsteği düzeltin
- Kod
ERR_EMPTY_STAY- Durum
- 422
- Anlamı
checkOut≤checkIn- Çağıran
- İsteği düzeltin
- Kod
ERR_STAY_TOO_LONG- Durum
- 422
- Anlamı
- 30 geceden fazla
- Çağıran
- İsteği düzeltin
- Kod
ERR_STAY_IN_PAST- Durum
- 422
- Anlamı
- Giriş referans tarihinden önce
- Çağıran
- İsteği düzeltin
- Kod
ERR_STAY_TOO_FAR- Durum
- 422
- Anlamı
- Giriş referans tarihinden 732 günden fazla sonra
- Çağıran
- İsteği düzeltin
- Kod
ERR_NO_TRAVELLERS- Durum
- 422
- Anlamı
- yolcu yok
- Çağıran
- İsteği düzeltin
- Kod
ERR_TOO_MANY_TRAVELLERS- Durum
- 422
- Anlamı
- 20'den fazla yolcu
- Çağıran
- İsteği düzeltin
- Kod
ERR_INVALID_AGE- Durum
- 422
- Anlamı
- Yaş negatif veya 120'nin üzerinde
- Çağıran
- İsteği düzeltin
- Kod
ERR_BOARD_MISSING- Durum
- 422
- Anlamı
boardeksik (/v1/price,/v1/search,priceCheck)- Çağıran
- İsteği düzeltin
- Kod
ERR_NOW_MISMATCH- Durum
- 422
- Anlamı
priceCheck.nowreferans tarihi değil- Çağıran
- Alanı çıkarın
- Kod
ERR_VALIDATION- Durum
- 422
- Anlamı
- Metin çok uzun:
idemKey,reference(128),leadPaxName(255),metadata.correlationId(64);messagealanı ve sınırı belirtir - Çağıran
- İsteği düzeltin
- Kod
ERR_QUANTITY_INVALID- Durum
- 400
- Anlamı
quantity1–1.000.000 dışında- Çağıran
- İsteği düzeltin
- Kod
ERR_INVALID_IDEM_KEY- Durum
- 400
- Anlamı
idemKeyeksik (/v1/book,/v1/cancel)- Çağıran
- İsteği düzeltin
- Kod
ERR_INVALID_BUCKET- Durum
- 400
- Anlamı
roomeksik (/v1/book,priceCheckile ve olmadan)- Çağıran
- İsteği düzeltin
- Kod
ERR_INVALID_STAY- Durum
- 400
- Anlamı
- Konaklama geçersiz (satışta koruma; API bunu önceden
ERR_BAD_DATE/ERR_EMPTY_STAYile kontrol eder) - Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_PAGE_SIZE- Durum
- 422
- Anlamı
pageSize1–100 (/v1/search; açık arama: 1'den arama profiline kadar) veya 1–1000 (/v1/content/*) dışında- Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_CURSOR- Durum
- 422
- Anlamı
- Cursor okunamıyor, değiştirilmiş veya süresi dolmuş (ör. sunucu yeniden başlatıldıktan sonra; açık arama: verilişinden 15 dakika sonra); Content API:
cursor/sinceokunamıyor, değiştirilmiş veya başka bir anahtardan - Çağıran
cursorolmadan yeniden başlayın veya dizini yeniden alın
- Kod
ERR_CURSOR_MISMATCH- Durum
- 422
- Anlamı
- Cursor başka bir isteğe veya başka bir anahtara ait (
/v1/search,/v1/search/open) - Çağıran
- İsteği düzeltin
- Kod
ERR_UNKNOWN_DESTINATION- Durum
- 422
- Anlamı
cursorolmadan/v1/searchveya/v1/search/open:destinationveyadestinations[i]için bu anahtara ait otel yok (büyük/küçük harf önemlidir)- Çağıran
- Kodu
GET /v1/destinations'dan alın (4.5)
- Kod
ERR_BAD_WINDOW- Durum
- 422
- Anlamı
- açık arama ve tarih matrisi:
arrivalFrom/arrivalToeksik veyaarrivalTo,arrivalFrom'dan önce - Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_NIGHTS- Durum
- 422
- Anlamı
- açık arama ve tarih matrisi:
nightsMin/nightsMaxeksik, < 1 veyanightsMin>nightsMax - Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_TARGET- Durum
- 422
- Anlamı
- açık arama:
destinationsvehotelsbirlikte, boş liste, boş kod veya arama profili yalnızca tekil hedeflere izin verdiği halde ikisi de yok; tarih matrisi:hoteleksik - Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_SORT- Durum
- 422
- Anlamı
- açık arama:
sortbilinmiyor (price,pricePerNight,hotel) - Çağıran
- İsteği düzeltin
- Kod
ERR_BAD_FILTER- Durum
- 422
- Anlamı
- açık arama ve tarih matrisi: boş
boards/boardTypes/roomslistesi veya boş giriş, bilinmeyen pansiyon türü, fiyat filtresi negatif veyaminTotalCents>maxTotalCents,currencyüç büyük harfli bir kod değil; otel ana verilerine göre filtre biçimi dışında (category,regions,geo, 4a.2) – mesaj alanı belirtir - Çağıran
- İsteği düzeltin
- Kod
ERR_WINDOW_TOO_WIDE- Durum
- 422
- Anlamı
- açık arama veya tarih matrisi: varış penceresi arama profilinin izin verdiğinden geniş (
maxWindowDaysveyamatrixMaxWindowDays,messagesınırı belirtir) - Çağıran
- pencereyi bölün veya daraltın
- Kod
ERR_NIGHTS_NOT_ALLOWED- Durum
- 422
- Anlamı
- açık arama: süre izin verilen sürelerin dışında veya
nightsMax - nightsMin + 1aralığı çok geniş; tarih matrisi: süre izin verilen sürelerin dışında (messagesınırı belirtir) - Çağıran
- süreyi ayarlayın
- Kod
ERR_SEARCH_TOO_BROAD- Durum
- 422
- Anlamı
- açık arama: istekte çok fazla
destinationsveyahotelsya da arama kapsamında çok fazla otel; tarih matrisi:matrixMaxCellsdeğerinden fazla hücre (messagesınırı belirtir) - Çağıran
- daraltın
- Kod
ERR_CURRENCY_REQUIRED- Durum
- 422
- Anlamı
- açık arama: arama kapsamındaki oteller birden fazla sözleşme para biriminde fiyatlandırıyor,
currencyeksik (messagebunları belirtir) - Çağıran
currencybelirtin
### fehler-aufenthalt-zu-lang
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}]}
}{"errorCode": "ERR_STAY_TOO_LONG", "message": "checkOut: Aufenthalt laenger als 30 Naechte"}### fehler-anreise-vergangen
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}]}
}{"errorCode": "ERR_STAY_IN_PAST", "message": "checkIn: {{gestern}} liegt vor dem Stichtag {{heute}} (Serverdatum)"}Çok uzun metinler satıştan önce reddedilir, asla kısaltılmaz:
### fehler-text-zu-lang
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"
}{"errorCode": "ERR_VALIDATION", "message": "idemKey: zu lang (129 Zeichen, hoechstens 128)"}Konaklama düzeni dışında yanlış yazılmış bir alan reddedilmez, ancak belirtilir – burada bu yüzden zorunlu alan eksik kalır ve yanıt her ikisini de söyler:
### fehler-tippfehler-feld
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}]}
}{"errorCode": "ERR_BAD_DATE", "message": "checkIn: fehlt (Pflichtfeld, JJJJ-MM-TT)",
"warnings": ["unbekanntes Feld 'checke' — ignoriert (Tippfehler?)"]}Başarılı bir yanıttaki uyarılar:
### hinweise-now-und-waehrung
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}]}
}{
"room": "EZ",
"currency": "EUR",
"rounding": {"mode": "Commercial", "decimalPlaces": 2, "scope": "Person"},
"totalCents": 12500,
"perTravellerCents": [12500],
"breakdown": [
{"chargeType": "BaseCharge", "code": "Base", "traveller": 0, "night": 0, "amountExact": "70.00", "amountCents": 7000},
{"chargeType": "BaseCharge", "code": "ExtraDay", "traveller": 0, "night": 1, "amountExact": "55.00", "amountCents": 5500}
],
"availability": {"configured": true, "available": true, "minFree": 5},
"warnings": [
"now: '{{gestern}}' ignoriert — Stichtag ist das Serverdatum {{heute}}",
"currency: angefragt 'USD', der Vertrag rechnet in 'EUR' (keine Umrechnung)"
]
}7.3 Stok, fiyat, satış
- Kod
ERR_HOTEL_NOT_FOUND- Durum
- 404
- Anlamı
- Otel bu anahtar için yok (ayrıca: başka tur operatörü, yayınlanmamış, müşteri grubunun özel fiyatı hesaplanamıyor – bkz. 1.1)
- Çağıran
- İsteği düzeltin; aksi halde bilinen bir otelde tur operatörünü bilgilendirin
- Kod
ERR_ROOM_NOT_FOUND- Durum
- 404
- Anlamı
- Oda bu otelde yok (tarih matrisi:
rooms[i]) - Çağıran
- İsteği düzeltin
- Kod
ERR_BOOKING_NOT_FOUND- Durum
- 404
- Anlamı
- Rezervasyon bilinmiyor veya bu anahtar için görünür değil
- Çağıran
- Referansı/anahtarı kontrol edin
- Kod
ERR_REFERENCE_AMBIGUOUS- Durum
- 409
- Anlamı
- kendi
referencedeğeriniz birden fazla rezervasyonla eşleşiyor (/v1/booking);messageTA-…referanslarını belirtir (test anahtarı:SB-…) - Çağıran
- TourAPI referansıyla okuyun; kendi referanslarınızı benzersiz tutun
- Kod
ERR_TENANT_NOT_FOUND- Durum
- 404
- Anlamı
- Tur operatörü (artık) aktif değil, yalnızca satış/iptal
- Çağıran
- Bildirin
- Kod
ERR_BOARD_NOT_OFFERED- Durum
- 422
- Anlamı
- Pansiyon tipi sunulmuyor (kod tam olarak sözleşmedeki gibi;
/v1/price,/v1/prices,priceCheck; açık arama:boards[i]arama kapsamındaki hiçbir otel tarafından sunulmuyor; tarih matrisi:boards[i]otelde yok veya hiçbir pansiyon tipiboards/boardTypesile uyuşmuyor); aramadadiagnostics.reasonsveyacoverage.reasonsiçinde neden - Çağıran
- İsteği düzeltin
- Kod
ERR_OCCUPANCY_NOT_ALLOWED- Durum
- 422
- Anlamı
- Konaklama düzeni hiçbir odaya (veya istenen odaya) uymuyor
- Çağıran
- farklı konaklama düzeni/farklı oda
- Kod
ERR_STAY_LENGTH_NOT_ALLOWED- Durum
- 422
- Anlamı
- odanın bir satış kuralı farklı bir konaklama süresi gerektiriyor (3.4); aramada
diagnostics.reasonsiçinde neden - Çağıran
- Süreyi değiştirin
- Kod
ERR_ARRIVAL_DAY_NOT_ALLOWED- Durum
- 422
- Anlamı
- bir satış kuralı farklı bir giriş/çıkış haftanın günü gerektiriyor (3.4)
- Çağıran
- Seyahat günlerini kaydırın
- Kod
ERR_TRAVEL_DATES_NOT_ALLOWED- Durum
- 422
- Anlamı
- konaklama bir kuralın satış penceresi dışında (3.4)
- Çağıran
- farklı dönem
- Kod
ERR_BOARD_NOT_ALLOWED- Durum
- 422
- Anlamı
- pansiyon tipi bu konaklama için satılmıyor (3.4)
- Çağıran
- farklı pansiyon tipi
- Kod
ERR_LEAD_TIME_NOT_ALLOWED- Durum
- 422
- Anlamı
- giriş, bir satış kuralının release süresi içinde; referans tarihinden itibaren sayılır (3.4)
- Çağıran
- daha geç giriş
- Kod
ERR_BOARD_NOT_AVAILABLE- Durum
- 422
- Anlamı
- pansiyon tipi bu yolcu grubuna satılmıyor, ek ücreti farklı bir bileşim gerektiriyor (3.5);
/v1/pricesiçinderooms[].errors[]kaydı, aramadadiagnostics.reasonsiçinde neden - Çağıran
- farklı pansiyon tipi/konaklama düzeni
- Kod
ERR_ROOM_RESTRICTION_INVALID- Durum
- 422
- Anlamı
- sözleşmedeki bir satış kuralı değerlendirilemiyor
- Çağıran
- Bildirin
- Kod
ERR_NO_SECTION- Durum
- 422
- Anlamı
- bir gece için fiyat yok (sezon sözleşmede yok); başka bir oda hesaplanıyorsa
/v1/pricesiçinderooms[].errors[]kaydı,roomolmadan/v1/price'tawarningsiçinde, aramadadiagnostics.roomErrorsiçinde - Çağıran
- farklı dönem
- Kod
ERR_NO_PRICE- Durum
- 422
- Anlamı
- istek için rezerve edilebilir oda yok, daha kesin bir neden olmadan
- Çağıran
- farklı dönem/farklı konaklama düzeni
- Kod
ERR_OCCUPANCY_NIGHT_UNCOVERED- Durum
- 422
- Anlamı
- Sözleşmenin konaklama düzeni kuralları bir geceyi kapsamıyor
- Çağıran
- Bildirin
- Kod
ERR_OCCUPANCY_INCONSISTENT_MCA- Durum
- 422
- Anlamı
- Minimum doluluk konaklama içinde değişiyor (desteklenmiyor)
- Çağıran
- daha kısa dönem veya bildirin
- Kod
ERR_OCCUPANCY_INCONSISTENT_CHILDREN- Durum
- 422
- Anlamı
- bir yolcu konaklama içinde bir kez çocuk, bir kez yetişkin (odanın çocuk yaş aralığı sezona göre değişiyor; desteklenmiyor)
- Çağıran
- daha kısa dönem veya bildirin
- Kod
ERR_OCCUPANCY_INCONSISTENT_INFANTS- Durum
- 422
- Anlamı
- bir bebek konaklama içinde bir kez doluluğa sayılıyor, bir kez sayılmıyor (odanın konaklama düzeni kuralı sezona göre değişiyor) ve bir ek ücret veya indirim kişi sayısına bağlı; belirsiz
- Çağıran
- daha kısa dönem veya bildirin
- Kod
ERR_CHILDREN_ORDER_MISSING- Durum
- 422
- Anlamı
- sözleşme önce en büyük mü yoksa en küçük çocuğun mu sayılacağını belirlemiyor ve bu çocuklar için bu bir fiyat farkı yaratıyor (sözleşme hatası)
- Çağıran
- Bildirin
- Kod
ERR_INVALID_AMOUNT- Durum
- 422
- Anlamı
- sözleşmedeki bir tutar veya yüzde okunamıyor
- Çağıran
- Bildirin
- Kod
ERR_AMOUNT_OVERFLOW- Durum
- 422
- Anlamı
- fiyat gösterilebilir sent aralığını aşıyor (sözleşme hatası)
- Çağıran
- Bildirin
- Kod
ERR_CURRENCY_NOT_AVAILABLE- Durum
- 422
- Anlamı
priceCheck.currencysözleşme para birimine uymuyor veya sözleşme para birimi bilinmiyor; açık aramadacoverage.reasonsiçinde neden (otel istenenden başka veya bilinmeyen bir para biriminde fiyatlandırıyor); tarih matrisi: aynısı 422 olarak- Çağıran
- İsteği düzeltin veya bildirin
- Kod
ERR_PRICE_DRIFT- Durum
- 409
- Anlamı
- güncel fiyat
priceCheck'ten sapıyor - Çağıran
- yeni fiyatı gösterin, yeni
expectedCentsile rezervasyon yapın
- Kod
ERR_SOLD_OUT- Durum
- 422
- Anlamı
- Gece dolu
- Çağıran
- tekrarlamayın
- Kod
ERR_STOP_SALE- Durum
- 422
- Anlamı
- Satış durdurma
- Çağıran
- tekrarlamayın
- Kod
ERR_INVENTORY_CLOSED- Durum
- 422
- Anlamı
- Gece kapalı veya yalnızca talep üzerine
- Çağıran
- tekrarlamayın
- Kod
ERR_NO_INVENTORY- Durum
- 422
- Anlamı
- en az bir gece için kapasite tanımlı değil (rezervasyon ve arama nedeni aynı)
- Çağıran
- tekrarlamayın
- Kod
ERR_NOT_AVAILABLE- Durum
- –
- Anlamı
- yalnızca aramada neden olarak: her gecenin kapasitesi var, ancak her biri açık değil (rezervasyon:
ERR_SOLD_OUT,ERR_STOP_SALE,ERR_INVENTORY_CLOSED) - Çağıran
- –
- Kod
ERR_OUTSIDE_PRICE_FILTER- Durum
- –
- Anlamı
- yalnızca neden olarak: açık aramada otelin her teklifi, tarih matrisinde hücrenin her teklifi
minTotalCents/maxTotalCentsdışında - Çağıran
- –
- Kod
ERR_NO_CATEGORY- Durum
- –
- Anlamı
- yalnızca neden olarak (açık arama; tarih matrisinde otelin her hücresi):
categoryfiltresi, otelin otel ana verilerinde resmi kategorisi yok - Çağıran
- Tur operatörü: kategoriyi girin
- Kod
ERR_NO_REGION- Durum
- –
- Anlamı
- yalnızca neden olarak (açık arama; tarih matrisinde otelin her hücresi):
regionsfiltresi, otelin otel ana verilerinde bölgesi yok - Çağıran
- Tur operatörü: bölgeyi girin
- Kod
ERR_NO_GEO- Durum
- –
- Anlamı
- yalnızca neden olarak (açık arama; tarih matrisinde otelin her hücresi):
geofiltresi, otelin otel ana verilerinde koordinatı yok - Çağıran
- Tur operatörü: koordinatları girin
- Kod
ERR_GROUP_LIMIT- Durum
- 422
- Anlamı
- Müşteri grubunun tahsisi tükenmiş veya oda ve gece için mevcut değil
- Çağıran
- tekrarlamayın
- Kod
ERR_IDEMPOTENCY_MISMATCH- Durum
- 409
- Anlamı
idemKeyzaten farklı rezervasyon verileriyle kullanılmış- Çağıran
- Çağıranın hatası: benzersiz anahtarlar verin
- Kod
ERR_IDEM_KEY_RELEASED- Durum
- 409
- Anlamı
idemKeyiptal edilmiş bir rezervasyona ait- Çağıran
- yeni
idemKeykullanın
- Kod
ERR_SANDBOX_LIMIT- Durum
- 422
- Anlamı
- Test anahtarı: bu erişimin 5.000'den fazla açık test rezervasyonu var (Bölüm 11.2)
- Çağıran
- Test rezervasyonlarını iptal edin
### fehler-verpflegung-nicht-angeboten
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}]}
}{"errorCode": "ERR_BOARD_NOT_OFFERED", "message": "boards: Verpflegung 'AI' wird nicht angeboten"}Aynısı /v1/price için de geçerlidir – odanın sunmadığı bir pansiyon tipi asla
pansiyon tipi olmayan fiyattan hesaplanmaz:
### fehler-verpflegung-preis
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}]}
}{"errorCode": "ERR_BOARD_NOT_OFFERED", "message": "board: Verpflegung 'AI' wird nicht angeboten"}7.4 Yük ve işletim
- Kod
ERR_RATE_LIMITED- Durum
- 429
- Anlamı
- bu anahtardan çok fazla istek (Bölüm 8); açık arama ve tarih matrisi: arama profilinin istek hızı aşıldı (ikisi birlikte)
- Çağıran
Retry-Aftersonrasında tekrarlayın
- Kod
ERR_SEARCH_BUSY- Durum
- 429
- Anlamı
- tur operatörünün çok fazla eşzamanlı araması (açık arama: arama profiline göre anahtarın da)
- Çağıran
Retry-After(1 sn) sonrasında tekrarlayın
- Kod
ERR_SEARCH_TIMEOUT- Durum
- 503
- Anlamı
- Arama süre sınırını (10 sn) aştı
- Çağıran
- daraltın (
destination/destinations, daha küçük pencere), sonra tekrarlayın
- Kod
ERR_PRICE_TIMEOUT- Durum
- 503
- Anlamı
roomolmadan/v1/priceveya/v1/pricessüre sınırını (2 sn) aştı- Çağıran
roomile/v1/priceçağrısına geçin (/v1/pricesiçin sınır her zaman geçerlidir,roomveboardsile de), sonra tekrarlayın
- Kod
ERR_BOOKING_DISABLED- Durum
- 503
- Anlamı
- Satış/iptal bu düğümde etkin değil (test anahtarı: sandbox etkin değil – bir test anahtarı asla canlı rezervasyon yapmaz)
- Çağıran
- Tekrarlayın, kalıcıysa: bildirin
- Kod
ERR_BOOKING_BUSY- Durum
- 503
- Anlamı
- Rezervasyon/iptal aynı oteldeki eşzamanlı işlemler nedeniyle gerçekleşmedi, hiçbir şey rezerve veya iptal edilmedi
- Çağıran
Retry-After(1 sn) sonrasında aynıidemKeyile tekrarlayın
- Kod
ERR_INTERNAL- Durum
- 500
- Anlamı
- dahili hata, ör. veritabanına erişilemiyor (hesaplama çekirdeğinde ihlal edilen bir invaryant, sorgu endpoint'lerinde 422 olarak gelir); açık arama: sonuç kanıtlanamıyor (4a.4)
- Çağıran
- Ara vererek tekrarlayın;
/v1/book'ta aynıidemKeyile
- Kod
ERR_INVENTORY_DRIFT- Durum
- 500
- Anlamı
- Kontenjan invaryantı ihlal edildi, hiçbir şey satılmadı
- Çağıran
- Bildirin
- Kod
ERR_INVENTORY_STATUS_UNKNOWN- Durum
- 500
- Anlamı
- kontenjanda bilinmeyen günlük durum, hiçbir şey satılmadı
- Çağıran
- Bildirin
- Kod
ERR_RELEASE_DRIFT- Durum
- 500
- Anlamı
- İptal, kontenjan invaryantı nedeniyle engellendi, hiçbir şey iptal edilmedi
- Çağıran
- Bildirin
7.5 Sözleşme verileri (tur operatöründeki hatalar)
Bu kodlar, otelin sözleşmesi TourAPI'nin hesaplamadığı (veya bu şekilde hesaplamadığı) bir kural
içerdiğinde hesaplama çekirdeğinden gelir. Sözleşme önceden kontrol edildiği için yayınlandıktan sonra
görülmemeleri gerekir. Durum her zaman 422. Çağıran: Bildirin (otel,
dönem ve message ile); aramada diagnostics.reasons içinde neden olarak
(otel düşer) veya diagnostics.roomErrors içinde (tek oda atlanır) görünürler.
room olmadan /v1/price'ta, başka bir oda hesaplanabildiği sürece etkilenen oda atlanır ve
warnings içinde belirtilir; /v1/prices etkilenen pansiyon tiplerini rooms[].errors[]
içinde belirtir ve geri kalanını fiyatlar (Bölüm 3.2). ERR_NEGATIVE_TRAVELLER_PRICE ve
ERR_NEGATIVE_PERCENT_BASE konaklama düzenine ve pansiyon tipine bağlıdır: Yazma kapısı bunlara karşı uyarır,
ancak sözleşmeye izin verir; bu nedenle yayınlandıktan sonra da gelebilirler. /v1/prices
o zaman yalnızca etkilenen pansiyon tipini atlar (rooms[].errors[], Bölüm 3.2).
- Kod
ERR_NO_BASECHARGE- Anlamı
- Temel fiyat eksik
- Kod
ERR_SECTION_BAD_DATE,ERR_BOARD_BAD_DATE,ERR_OCCUPANCY_BAD_DATE- Anlamı
- sözleşmede geçersiz tarih
- Kod
ERR_OCCUPANCY_INCOMPLETE- Anlamı
- Konaklama düzeni kuralı eksik
- Kod
ERR_AMBIGUOUS_BOARDCHARGE- Anlamı
- iki pansiyon tipi ek ücreti aynı gecede aynı kişiye uygulanabiliyor; hangisinin geçerli olduğu belirsiz (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_AMBIGUOUS_BASECHARGE,ERR_AMBIGUOUS_SECTION- Anlamı
- bir sezonda aynı tipte iki temel fiyat veya aynı gün için iki sezon; hangi fiyatın geçerli olduğu belirsiz (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_AMBIGUOUS_FREENIGHT- Anlamı
- aynı konaklama için iki ücretsiz gece teklifi devreye girebiliyor; ikincisinin hangi geceleri bağışladığı belirlenmemiş (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_UNSUPPORTED_FREENIGHT,ERR_UNSUPPORTED_REDUCTION_MODE- Anlamı
- TourAPI'nin hesaplamadığı bir biçimde ücretsiz gece teklifi (ör. yüzde yerine sabit tutar, kişi kısıtlaması, „büyük/küçük“ gece seçimi)
- Kod
ERR_NEGATIVE_TRAVELLER_PRICE- Anlamı
- tüm ek ücret ve indirimlerden sonra bir yolcu 0'dan az öderdi (ör. hiçbir ücreti olmayan bir çocuğa kişi başı sabit indirim veya %100'ü aşan üst üste indirimler). Bir yolcu asla 0'dan az ödemez;
messageyolcuyu ve ek ücreti/indirimi belirtir. Yüzde indirimleri, yolcunun çocuk/kişi indiriminden sonra borçlu olduğu tutar üzerinden hesaplanır ve hatayı tek başına tetiklemez
- Kod
ERR_NEGATIVE_PERCENT_BASE- Anlamı
- bir çocuk/kişi indirimi (sabit tutar), etki ettiği günlük fiyattan veya pansiyon tipinden büyük; bunun üzerindeki bir yüzde indirimi ek ücrete dönüşür, bir ücretsiz gece (ör. „7=6“) konaklamayı pahalılaştırırdı.
messageek ücreti/indirimi veya ücretsiz geceyi, yolcuyu ve geceyi belirtir
- Kod
ERR_UNSUPPORTED_OCCUPANCY_PRICEBLOCK- Anlamı
- Doluluğa göre temel fiyat (harici bir teslimattan, ör. “tam 1 kişi” / “2 kişi ve üzeri”) TourAPI'nin hesaplamadığı bir biçimde — ya da böyle bir odada bebek seyahat ediyor (tedarikçi odayı bebekle satmıyor)
- Kod
ERR_UNSUPPORTED_GUESTCHARGE_OBJECT- Anlamı
- Bir oda fiyatına (obje fiyatı) kişi indirimi (ör. çocuk indirimi): etki edebileceği kişi başı bir fiyat yok (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_UNSUPPORTED_COMBIGROUP- Anlamı
- bir teklif 0 numaralı kombinasyon grubunda münhasır; 0 grubu EDF'de grubu olmayan tüm teklifleri de temsil eder, bir EDF alıcısı farklı hesaplardı (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_COMPATIBLE_WITH_INVALID- Anlamı
- bir teklifin “yalnızca şu gruplarla birleştirilebilir” listesi belirsiz: bir grup iki kez, 0..2147483647 dışında ya da “grupta yalnızca biri” ile birlikte (yazma kapısı buna izin vermez, yalnızca eski kayıtlar)
- Kod
ERR_CALCMODE_MISSING,ERR_CALCMODE_UNSUPPORTED- Anlamı
- Odanın hesaplama türü eksik veya desteklenmiyor
- Kod
ERR_BASE_BOARD_INVALID,ERR_BASE_BOARD_CHARGED- Anlamı
- Odanın temel pansiyonu (taban fiyata dahil pansiyon) geçersiz veya kendi ek ücretini taşıyor (yazma kapısı buna izin vermez, yalnızca eski veri)
- Kod
ERR_MINCHARGEDPERSONS_MISSING,ERR_INVALID_MIN_CHARGED_PERSONS- Anlamı
- Minimum ödeme yapan kişi sayısı eksik veya geçersiz
- Kod
ERR_INVALID_ENUM,ERR_INVALID_WEEKDAY_MASK- Anlamı
- geçersiz numaralandırma değeri veya haftanın günü maskesi
- Kod
ERR_MISSING_APPLIANCE_TYPE,ERR_MISSING_AMOUNT_OR_PERCENT,ERR_MISSING_BOARD_CODE,ERR_AMOUNT_PERCENT_CONFLICT,ERR_DUPLICATE_APPLIANCE_CODE,ERR_EXTRA_TYPE_INVALID- Anlamı
- Ek ücret veya indirim eksik ya da çelişkili
- Kod
ERR_EXTRACALC_UNSUPPORTED,ERR_UNSUPPORTED_APPLIANCE_TYPE,ERR_UNSUPPORTED_APPLYTOBOARD,ERR_UNSUPPORTED_EXTRA_REF,ERR_UNSUPPORTED_GUESTCHARGE_LINK,ERR_UNSUPPORTED_GUESTCHARGE_TYPE,ERR_UNSUPPORTED_INVERT,ERR_UNSUPPORTED_MANDATORY,ERR_UNSUPPORTED_MCA_AGEWINDOW,ERR_UNSUPPORTED_MCA_RANGE,ERR_UNSUPPORTED_RESTRICTION,ERR_UNSUPPORTED_VARMCP_PERSTAY- Anlamı
- TourAPI'nin hesaplamadığı sözleşme kuralı
7.6 EDF teslimatı (/v1/export/edf/*, Bölüm 10)
- Kod
ERR_EXPORT_BAD_CURSOR- Durum
- 400
- Anlamı
epoch/sinceeksik veya okunamıyor,untilgeçerli bir zincir anahtarı değil,max_bytes≥ 65536 bir sayı değil, parametre iki kez verilmiş,untilolmadan bir durumun ortasında sayfa,full'ünepoch/since/untilolmadan sonraki sayfası- Çağıran
- İsteği düzeltin veya zinciri yeniden başlatın
- Kod
ERR_EXPORT_NOT_ALLOWED- Durum
- 403
- Anlamı
- Dışa aktarım yetkisi olmayan anahtar
- Çağıran
- Tur operatörüne sorun, tekrarlamayın
- Kod
ERR_EXPORT_EPOCH- Durum
- 409
- Anlamı
epochuymuyor (feed yeniden oluşturuldu) veya durum (since,until, onayınseqdeğeri) güncel teslimat durumunun üzerinde (son teslim edilen durumdan büyük)- Çağıran
fullçekin
- Kod
ERR_EXPORT_CURSOR_EXPIRED- Durum
- 410
- Anlamı
- Durum saklama süresinden eski
- Çağıran
fullçekin
- Kod
ERR_EXPORT_NOT_READY- Durum
- 503
- Anlamı
- Bu anahtar için teslimat henüz oluşturulmadı, geçici olarak güncel değil (teslimat 2 dakikadan fazla geride) veya düğümde yapılandırılmamış
- Çağıran
Retry-Aftersonrasında tekrarlayın; kalıcıysa: bildirin
Ayrıca /v1/export/edf/* üzerinde: 7.1'deki 401/403 (ERR_TENANT_SUSPENDED,
ERR_KEY_GROUP_INACTIVE), 422 ERR_UNKNOWN_FIELD (bilinmeyen parametre veya onay alanı)
ve döngü için 429 ERR_RATE_LIMITED (10.3; full'de 3600 sn'ye kadar Retry-After – körü körüne
beklemeyin, bir sonraki döngüyü planlayın).
7.7 Otel içerikleri (/v1/content/*, Bölüm 12)
- Kod
ERR_CONTENT_NOT_ALLOWED- Durum
- 403
- Anlamı
- İçerikler tur operatörü için etkin değil (ayrıca: test ortamına bu kurulumda hizmet verilmiyor) veya anahtarın içerik yetkisi yok
- Çağıran
- Tur operatörüne sorun, tekrarlamayın
- Kod
ERR_LANGUAGE_NOT_OFFERED- Durum
- 422
- Anlamı
lang, tur operatörünün içerik dillerinden olmayan bir dil içeriyor (katalogda: etiket dili değil); sunulanlarwarningsiçindedir- Çağıran
- İsteği düzeltin
- Kod
ERR_CONTENT_CURSOR_EXPIRED- Durum
- 410
- Anlamı
sinceakışın saklama ufkunun (30 gün) öncesinde- Çağıran
- Dizini yeniden alın, onun
feedToken'ı ile devam edin
- Kod
ERR_CONTENT_NOT_READY- Durum
- 503
- Anlamı
- İçerikler veya görsel adresleri bu düğümde kurulu değil
- Çağıran
Retry-Aftersonrasında tekrarlayın; kalıcıysa: Bildirin
Ayrıca /v1/content/* üzerinde: 7.1'den 401/403, 404 ERR_HOTEL_NOT_FOUND (otel
anahtarın dizininde değil), 400 ERR_BAD_REQUEST, 422 ERR_BAD_PAGE_SIZE, ERR_BAD_CURSOR
ve 429 ERR_RATE_LIMITED (anahtar başına hız, Bölüm 8). Bilinmeyen
sorgu parametreleri yok sayılır ve warnings içinde belirtilir.
8. Adalet: hız sınırı ve arama kapısı
- Kilit
- API anahtarı başına istek
- Sınır (varsayılan ayar)
- saniyede 200, kısa süreliğine 400'e kadar (token bucket)
- Yanıt
429 ERR_RATE_LIMITED+Retry-After
- Kilit
- tur operatörü başına eşzamanlı arama
- Sınır (varsayılan ayar)
- 8 (hesaplama süresi: çekirdeklerin dörtte biri, en az 1)
- Yanıt
429 ERR_SEARCH_BUSY+Retry-After: 1
- Kilit
- bir aramanın hesaplama süresi
- Sınır (varsayılan ayar)
- 10 sn
- Yanıt
503 ERR_SEARCH_TIMEOUT
- Kilit
roomolmadan/v1/priceve/v1/priceshesaplama süresi- Sınır (varsayılan ayar)
- 2 sn
- Yanıt
503 ERR_PRICE_TIMEOUT
- Sınırlar sunucu düğümü başına geçerlidir. Döngülere ve yük zirvelerine karşı bir korumadır, faturalandırılabilir bir kota değildir. İşletmeci bunları değiştirebilir.
Retry-Aftertam saniye cinsindendir (en az 1). Öncesinde tekrarlamayın; sonrasında aynı istekle (/v1/book'ta aynıidemKeyile) tekrarlayın.Retry-Afterdolmadan yeniden gönderen ve tekrar reddedilen,429yanıtını gecikmeli alır (bildirilen bekleme süresinin sonuna kadar, en fazla 1 sn). Bekleme süresi API anahtarı başına geçerlidir: aynı anahtarla birden fazla süreç paralel çalışıyorsa, gecikme bir429sonrasında göndermeye devam eden herkesi etkiler, kaç bağlantıyla olursa olsun. Bağlantı açık kalır.- Reddedilen anahtarlar (
401,403 ERR_TENANT_SUSPENDED,403 ERR_KEY_GROUP_INACTIVE) gönderici IP'si başına sayılır: kısa sürede 20 retten sonra saniyede yalnızca 5 istek hemen yanıtlanır, diğerleri gecikmeli (en fazla 1 sn), kaç bağlantıyla olursa olsun. Durum ve yanıt aynı kalır. Geçerli anahtarlı istekler bundan asla etkilenmez. - Bilinmeyen yollar (
404) ve yanlış metotlar (405 ERR_METHOD_NOT_ALLOWED), reddedilen anahtarlarla aynı gönderici IP'si başına sınıra dahil edilir. /v1/health'in gönderici IP'si başına kendi sınırı vardır: 50 çağrı hemen, sonra saniyede 10 hemen, diğerleri gecikmeli (en fazla 1 sn). Yanıt her zaman güncel durumdur, asla bir ret değildir.- Reddedilen istekler kullanım olarak sayılmaz.
- Kesilmiş arama sayfaları hata değildir, bkz. 4.3.
Kısıtlama şöyle görünür (örnekler 10 sn'de 1 isteğe izin veren bir örneğe karşı çalışır):
### drossel-erste-anfrage
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
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}]}
}{"errorCode": "ERR_RATE_LIMITED", "message": "Anfrage-Rate dieses API-Keys ueberschritten"}Buna ait header: Retry-After: 10.
9. Idempotency ve eşzamanlılık
Rezervasyon:
idemKeyzorunludur ve çağırana aittir. Tur operatörü ve anahtar çevresi başına (müşteri grubu veya temel sözleşme) geçerlidir: İki müşteri grubu birbirini etkilemeden aynı anahtarı kullanabilir.- Aynı
idemKey, aynı rezervasyon verileri (otel, oda, konaklama, miktar) = aynı rezervasyon:200,alreadyBooked: true, aynı referans. Bir tekrarınreference,metadata,leadPaxNamevepriceCheckdeğerleri karşılaştırılmaz ve devralınmaz – ilk rezervasyon geçerlidir. - Aynı
idemKey, farklı rezervasyon verileri:409 ERR_IDEMPOTENCY_MISMATCH. - İptal edilmiş
idemKey:409 ERR_IDEM_KEY_RELEASED. - Idempotency kontrolü referans tarihi, sınırlar ve
priceCheck'ten önce gelir: Rezervasyon mevcutsa, tekrar onu gece yarısından sonra da (giriş artık geçmişte,priceCheck.nowartık referans tarihi değil) veya bir fiyat değişikliğinden sonra da onaylar. Yalnızca yeni biridemKeybu kontrollerden geçer. İsteğin biçim hataları (bilinmeyen alanlar, eksik zorunlu alanlar, çok uzun metinler) yine önceden reddedilir. - Bir
idemKey'in ilk rezervasyonu hâlâ sürüyorsa, bir tekrar onun sonucunu bekler ve ardından onu onaylar (200,alreadyBooked: true); ilki başarısız olursa tekrar yeni bir rezervasyon olarak çalışır. Bekleme çok uzun sürerse:Retry-Afterile503 ERR_BOOKING_BUSY– aynıidemKeyile tekrarlayın. - Aynı odanın iki eşzamanlı rezervasyonu kontenjanı asla aşırı dolduramaz: Her gece atomik olarak sayılır ve bir rezervasyon ya tüm geceleri alır ya hiçbirini.
- Rezervasyon veya iptal aynı oteldeki eşzamanlı işlemler nedeniyle gerçekleşmezse:
Retry-Afterile503 ERR_BOOKING_BUSY(Bölüm 7.4). Hiçbir şey rezerve veya iptal edilmemiştir; bekleme süresinden sonra aynıidemKeyile tekrarlayın. - Bir otel, onun için bir rezervasyon sürerken silinirse sıra geçerlidir: önce
rezervasyon yapıldıysa, o kalır; aksi halde
404 ERR_HOTEL_NOT_FOUND, hiçbir şey rezerve edilmez. - Zaman aşımı veya
5xxsonrasında rezervasyon yapılıp yapılmadığı belirsizdir: aynıidemKeyile tekrarlayın, asla yenisiyle değil.
İptal:
- Rezervasyonun
idemKeydeğeri üzerinden adreslenir. Çift iptal bir başarıdır (alreadyReleased: true). Aynı rezervasyonun eşzamanlı iptalleri kontenjanı tam olarak bir kez iade eder.
10. EDF teslimatı (önbellek dışa aktarımı)
Amaç: Bir alıcı, anahtarının tüm otellerinin fiyat ve müsaitliklerini
kendi önbelleğinde EDF dosyaları olarak tutar ve rezervasyondan önce canlı sorgular (/v1/price, sonra
/v1/book). Bağlayıcı olan her zaman /v1/book'tur; önbellek bir tekliftir, stok değildir.
Tam teslimat sözleşmesi (manifestin kanonik biçimi, sınırlar) işletmeciden talep üzerine
alınabilir.
- Metot/yol
GET /v1/export/edf/full[?max_bytes=N]- Yanıt
- Tam durumu içeren
200zip (büyük stoklarda ilk sayfa)
- Metot/yol
GET /v1/export/edf/full?epoch=E&since=S&until=K[&max_bytes=N]- Yanıt
- Tam durumun sonraki sayfasını içeren
200zip
- Metot/yol
GET /v1/export/edf/changes?epoch=E&since=S[&until=K][&max_bytes=N]- Yanıt
Sdurumundan sonraki tüm değişiklikleri içeren200zip; yeni bir şey yoksa204
- Metot/yol
POST /v1/export/edf/ack{"epoch": E, "seq": T}- Yanıt
204; „işlendi“ bildirir (yalnızca tur operatöründeki izleme için)
- Kapsam yalnızca anahtar üzerinden: Neyin teslim edileceğini anahtar belirler – bu anahtar için
/v1/searchve/v1/priceile aynı oteller ve fiyatlar (temel sözleşme, kendi fiyatıyla müşteri grubu, yalnızca tahsisli otellerle kontenjan grubu). Tur operatörünü veya grubu seçen bir parametre yoktur; bilinmeyen bir parametre422 ERR_UNKNOWN_FIELD'dır. - Dışa aktarım yetkisi: anahtar başına etkinleştirilir (tur operatörü yöneticisi, konsolda
anahtar satırında „Export erteilen“); yetki yoksa
403 ERR_EXPORT_NOT_ALLOWED. - Yalnızca yayınlananlar: Taslaklar teslimatı asla değiştirmez. Değişiklikler (yayınlama, satış durdurma, rezervasyon, kampanya, tahsis) en geç yaklaşık bir dakika sonra feed'de yer alır.
10.1 Paket
İlk giriş olarak manifest.json, ardından her otel için bir fiyat dosyası
(hotels/hotelonly/EDF----<tenant>-<hotel>.xml, EDF 5.1.6) ve bir allotment dosyası
(hotels/hotelonly/allotment/EDF----<tenant>-<hotel>.xml, HotelAllotmentRoot 1.012) içeren bir zip.
Kimlik manifestten veya BasicData'dan alınır, asla dosya adından alınmaz (kodlar -
içerebilir). Her dosyanın sha256 sağlama toplamı ve uzunluğu manifestte yer alır; bir paket ya tamamen
uygulanır ya hiç uygulanmaz.
objects içinde bir giriş ve removed içinde bir giriş:
{"path": "hotels/hotelonly/EDF----TEST-TENANT-A-TEST-HOTEL-BASE.xml", "kind": "hotel", "hotel": "TEST-HOTEL-BASE", "seq": 3, "sha256": "9f2c…", "bytes": 2210, "source_rev": 4}{"kind": "hotel", "hotel": "TEST-HOTEL-ALTAKTION", "seq": 5, "reason": "withdrawn:variant_error"}- Tombstone'lar: Geri çekilen oteller
removedaltında nedenleriyle yer alır (withdrawn:deleted,withdrawn:variant_error,withdrawn:not_exportable,withdrawn:no_currency,withdrawn:not_in_universe). Alıcı bunları kendi önbelleğinden siler. Birfullher zamanremoved: []içerir – önbelleği tamamen değiştirir. - Allotment dosyasının pattern'i: gece başına iki karakter (
PatternLength="2", MTS teslimatları gibi):00–99= bu anahtar için boş birimler,**= 99'dan fazla boş veya serbest satış,SS= satış durdurma,RR= talep üzerine; kapasitesiz bir gece00'dır. Bir allotment dosyası eksikse otel müsait değil kabul edilir. Oda başına yapı:<Allotments RoomCode="DZ"><Allotment Start="JJJJ-MM-TT" End="JJJJ-MM-TT" Pattern="…"/>;Pattern'in ilk iki karakteriStartgecesine, sonraki her çift bir sonraki geceye aittir. - Pattern ve
minFree:SS,RRve00açıkçaminFree0verir (rezerve edilemez); yalnızca**minFree'yi düşürmez ve-1şu anlama gelir: her gece**. Bir konaklamanın geceleri boyunca minimum, aynı anahtar için/v1/price'ınavailability.minFreedeğeridir (Bölüm 3.3'teki tablo) – ikisi de gece başına aynı kaynaktan gelir.
10.2 Tam durum, değişiklikler, onay
Başlangıçta ve 409/410 sonrasında alıcı tam durumu çeker. Manifestten
epoch ve to_seq değerlerini not eder. Tam durum bir pakete sığmazsa (10.000'den fazla dosya,
açılmış halde 1 GiB'den fazla veya max_bytes'tan fazla), sayfalar halinde gelir, bkz. aşağıda „Sayfalar“:
### export-voll
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{apiKey}}{
"format": "tourapi-edf-feed/1",
"tenant": "TEST-TENANT-A",
"scope": "",
"epoch": "{{exportEpoch}}",
"type": "full",
"from_seq": 0,
"to_seq": "{{*}}",
"more": false,
"generated_at": "{{*}}",
"rules": {"edf": "5.1.6", "allotment": "1.012", "spec": ""},
"objects": "{{*}}",
"removed": []
}Her 200/204 yanıtının header'ları: X-Export-Epoch, X-Export-Seq (son
tam durum), X-Export-From (teslimatın başladığı durum), X-Export-More;
bir changes paketinde ve more: true olan bir full sayfasında ayrıca
X-Export-Until (zincir anahtarı, bkz. aşağıda). Bir sayfa bir durumun ortasında biterse (manifestte to_after),
X-Export-Seq ondan önceki durumu belirtir – bir full'ün ilk sayfalarında yani
0. since, uygulama ve onay için belirleyici olan manifestteki to_seq/to_after'dır. Bir
müşteri grubunun anahtarı kendi grubunun durumunu (scope), grubun fiyatlarıyla alır:
### export-partner
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{rabattKey}}Ardından döngü içinde değişiklikleri sorgular. since, son uygulanan paketin
to_seq değeridir; zaten güncel durumdaysa içeriksiz 204 gelir:
### export-nichts-neu
GET {{baseUrl}}/v1/export/edf/changes?epoch={{exportEpoch}}&since={{exportSeq}}
X-Api-Key: {{apiKey}}Sayfalar (max_bytes): full ve changes sayfa zincirleridir. Bir sayfada en fazla
10.000 dosya ve açılmış halde 1 GiB bulunur; max_bytes=N ile sunucu ayrıca en fazla N baytlık
sayfalar keser (sayfa başına en az bir dosya); N en az 65536'dır (64 KiB), daha küçüğü
400 ERR_EXPORT_BAD_CURSOR'dır. İlk sayfa (parametresiz full veya
until olmadan changes) zincirin hedefini (güncel durumu) belirler ve bunu
zincir anahtarı olarak X-Export-Until içinde verir (full'de yalnızca more: true ise): anahtara ve epoch'a
bağlı, opak, mühürlü bir karakter dizisi (changes'te u1.…, full'de f1.…).
Alıcı sonraki sayfaları since=<to_seq> veya
since=<to_seq>:<to_after> (manifest to_after taşıyorsa) ve
until=<X-Export-Until> (önceki sayfanın değeri, URL kodlu, değiştirilmeden) ile, full'de ayrıca
epoch=<epoch> (ilk sayfanın değeri) ile, more false olana kadar sorgular. Her sayfa anahtarı yeniden
verir; anahtar son sayfadan sonra 15 dakika, full'de yalnızca tam olarak sonraki sayfanın
durumu için geçerlidir. Kendi seçilmiş bir until (sayı), yabancı veya süresi dolmuş bir anahtar
400 ERR_EXPORT_BAD_CURSOR'dır – o zaman zinciri yeniden başlatın. Bir full sayfası asla
removed taşımaz; ilki from_seq: 0'da, sonraki her biri önceki sayfanın to değerinde başlar. Durum ancak
zincirin sonunda tutarlıdır: uygulama (değiştirme) orada yapılır, tur operatörü
arada değişiklik yapmaya devam etse bile – zincir tam olarak hedefinde biter.
İptal ve tekrarlama: Bir paket, 200 zaten gönderildikten sonra başarısız olursa (örneğin
tur operatöründe bir dosya bu arada eksik olduğu için), sunucu bağlantıyı keser. Alıcı
o zaman bir iletim hatası görür (unexpected EOF, bağlantı sıfırlandı), asla
düzgün biçimde sonlandırılmış, kısaltılmış bir paket görmez. Yine de her paketi uygulamadan önce
manifestine karşı kontrol etmelidir: objects içindeki her dosya mevcut, uzunluk (bytes) ve sha256
doğru, fazladan dosya yok. Bir akış okuyucusu (ör. Java'nın ZipInputStream'i), bir giriş sınırında biten
bir zip'i kendiliğinden eksik olarak tanımaz. Kısa süreliğine başarısız olan bir sonraki sayfayı
(iletim hatası, yarıda kesilmiş veya okunamayan paket, 5xx), zinciri yeniden başlatmak yerine
aynı epoch/since/until ile tekrar sorgular (anahtar 15 dakika geçerlidir, 503 durumunda
Retry-After sonrasında) – yeni bir başlangıç döngü hakkını tüketir (full:
bir saat). Yalnızca 400 sonrasında zinciri yeniden başlatır, 409/410 sonrasında full çeker. Bir
zincir yarıda kalırsa eski durum geçerli kalır.
Uyguladıktan sonra alıcı durumu onaylar. Onay isteğe bağlıdır ve teslimatta hiçbir şeyi değiştirmez; tur operatörü bundan alıcının hangi durumu işlediğini görür:
### export-quittung
POST {{baseUrl}}/v1/export/edf/ack
Content-Type: application/json
X-Api-Key: {{apiKey}}
{"epoch": "{{exportEpoch}}", "seq": {{exportSeq}}}10.3 Hatalar ve döngü
- Durum
- 400
- Kod
ERR_EXPORT_BAD_CURSOR- Ne zaman
epoch/sinceeksik veya okunamıyor,untilgeçerli bir zincir anahtarı değil (yabancı, süresi dolmuş, sayı,full'de başka bir durum için),max_bytes≥ 65536 bir sayı değil,untilolmadan bir durumun ortasında sayfa, durum zincir hedefinin üzerinde,full'ünepoch/since/untilolmadan sonraki sayfası- Alıcının yapacağı
- İsteği düzeltin veya zinciri yeniden başlatın
- Durum
- 403
- Kod
ERR_EXPORT_NOT_ALLOWED- Ne zaman
- Dışa aktarım yetkisi olmayan anahtar
- Alıcının yapacağı
- Tur operatörüne sorun
- Durum
- 403
- Kod
ERR_KEY_GROUP_INACTIVE- Ne zaman
- Anahtarın müşteri grubu devre dışı (asla sessizce temel sözleşme)
- Alıcının yapacağı
- Tur operatörüne sorun
- Durum
- 409
- Kod
ERR_EXPORT_EPOCH- Ne zaman
epochuymuyor (feed yeniden oluşturuldu) veyasince/untilya da onayınseqdeğeri güncel teslimat durumunun üzerinde (son teslim edilen durumdan büyük; daha eski birsince'e izin verilir ve sonrasındaki her şeyi teslim eder)- Alıcının yapacağı
full
- Durum
- 410
- Kod
ERR_EXPORT_CURSOR_EXPIRED- Ne zaman
- Durum saklama süresinden (14 gün) eski
- Alıcının yapacağı
full
- Durum
- 429
- Kod
ERR_RATE_LIMITED- Ne zaman
- Döngü aşıldı, bkz. aşağıda
- Alıcının yapacağı
Retry-Aftersonrasında
- Durum
- 503
- Kod
ERR_EXPORT_NOT_READY- Ne zaman
- Bu anahtar için teslimat henüz hiç oluşturulmadı (yeni anahtar, yeni grup) veya teslimat geçici olarak güncel değil (verilerin 2 dakikadan fazla gerisinde)
- Alıcının yapacağı
Retry-Aftersonrasında, eski durum geçerli kalır
### export-stand-unlesbar
GET {{baseUrl}}/v1/export/edf/changes?epoch={{exportEpoch}}&since=gestern
X-Api-Key: {{apiKey}}### export-fremder-stand
GET {{baseUrl}}/v1/export/edf/changes?epoch=01J00000000000000000000000&since=1
X-Api-Key: {{partnerKey}}{"errorCode": "ERR_EXPORT_EPOCH", "message": "epoch veraltet (Feed neu aufgebaut) oder Stand neuer als der aktuelle Lieferstand — full abrufen"}### export-ohne-recht
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{poolKey}}{"errorCode": "ERR_EXPORT_NOT_ALLOWED", "message": "dieser API-Key hat kein Export-Recht (EDF-Lieferung) — der Veranstalter-Admin schaltet es frei"}Anahtar başına döngü: yeni bir full saatte en fazla bir kez, yeni bir changes zinciri
dakikada en fazla bir kez. Bir zincirin sonraki sayfaları (full veya changes,
zincir anahtarıyla) ve onayların kendi, cömert döngüsü vardır (saniyede 5, bir
seferde 50). Bir zincir başlangıcının hangi çağrısı döngü hakkını tüketir:
| Yanıt | döngü hakkını tüketir |
|---|---|
400 ERR_EXPORT_BAD_CURSOR, 422 ERR_UNKNOWN_FIELD (geçersiz istek, her işten önce kontrol edilir) | hayır |
503 ERR_EXPORT_NOT_READY (teslimat henüz hiç oluşturulmadı veya geçici olarak güncel değil) | hayır – Retry-After'a uyan 429 almaz |
200 (yarıda kesilmiş bir indirme dahil), 204 („yeni bir şey yok“), 409 ERR_EXPORT_EPOCH | evet |
Döngü kontrolü, epoch ve durum kontrolünden önce gelir. Eski
epoch'a sahip bir alıcı döngü içinde önce 429'u, ancak onun Retry-After süresinden sonra 409'u görür.
Örnek akış changes (ölçülmüş, döngü 1 dk):
- Zaman
- 0 sn
- İstek
changes?epoch=E&since=S&foo=1(yazım hatası)- Yanıt
422 ERR_UNKNOWN_FIELD- Alıcının yapacağı
- düzeltin; döngü hakkı tüketilmedi
- Zaman
- 0 sn
- İstek
changes?epoch=E&since=S- Yanıt
204- Alıcının yapacağı
- Döngü hakkı tüketildi; sonraki zincir en erken 60 sn sonra
- Zaman
- 0 sn
- İstek
changes?epoch=E&since=S, feed bu arada yeniden oluşturuldu (Eeski)- Yanıt
429 ERR_RATE_LIMITED,Retry-After: 60- Alıcının yapacağı
Retry-Aftersüresini bekleyin
- Zaman
- 60 sn
- İstek
- aynı çağrı
- Yanıt
409 ERR_EXPORT_EPOCH- Alıcının yapacağı
fullçekin (kendi döngüsü, saatte 1)
Bunun ötesinde anahtarın hız sınırı geçerlidir (Bölüm 8). Aynı saat içinde ikinci bir full:
### export-zu-oft
GET {{baseUrl}}/v1/export/edf/full
X-Api-Key: {{apiKey}}{"errorCode": "ERR_RATE_LIMITED", "message": "full hoechstens einmal je 1 h je API-Key (danach changes)"}10.4 Uygulama ve önbellekten hesaplama (referans alıcı)
TourAPI'nin tam olarak bu kuralları uygulayan ve her derlemede
gerçek API'ye karşı kontrol edilen bir referans alıcısı vardır: edf-empfaenger aracı (işletmeciden talep üzerine)
(pull, apply, stand, rechne, reset; anahtar yalnızca
EDF_EMPFAENGER_KEY ortam değişkeninden gelir). Teslimattan hesapladığı şey, test kümesinin her isteği için
aynı anahtarın /v1/price sonucuyla sent düzeyinde aynıdır – toplam fiyat, yolcu başına fiyat, seçilen oda,
available ve minFree, ret durumunda aynı kod; bu, geçersiz ve
birden fazla açıdan geçersiz istekler için de geçerlidir (hangi sınırın önce devreye girdiği). Referans alıcı ve
make e2e-export TourAPI'nin kaynak ağacında bulunur ve teslimatın parçası değildir: Siz
müşteri olarak anahtar ve erişim paketi alırsınız ve bu bölümün kurallarını kendi sisteminizde
uygularsınız – referans alıcı, bu kuralların işlediğinin kanıtıdır.
EDF_EMPFAENGER_KEY=… edf-empfaenger pull --dir <bestand> --api <baseUrl> [--max-bytes N] [--ohne-ack]
edf-empfaenger stand --dir <bestand>
edf-empfaenger rechne --dir <bestand> --anfragen anfragen.json [--heute JJJJ-MM-TT]anfragen.json bir listedir; her istek için hotel, room (isteğe bağlı, yoksa = en uygun fiyatlı
müsait oda), board, checkIn, checkOut ve yolcuların yaşları ages olarak
(/v1/price'taki gibi occupancy.travellers değil), ör.
[{"hotel": "TEST-HOTEL-BASE", "room": "DZ", "board": "RO", "checkIn": "2026-10-27",
"checkOut": "2026-10-29", "ages": [40, 38]}]. Yanıt her istek için anfrage (indeks),
room, currency, totalCents, perTravellerCents, availability (available, minFree)
veya errorCode belirtir.
- Ya hep ya hiç: Paketi kontrol edin (dosya başına sha256 ve uzunluk), yeni durumu
eskisinin yanında eksiksiz kurun, ardından atomik olarak geçiş yapın; ancak bundan sonra
epochveto_seqkaydedilmiş sayılır. Sayfalı bir zincir (fullgibichangesde) ancak zincirin sonunda (more: false) geçiş yapılır; yarıda kalırsa eski durum geçerli kalır. Birfullzinciri her zamanfrom_seq: 0ile başlar; birfullsonraki sayfası yalnızca açık zincire bağlanır, asla kaydedilmiş bir duruma bağlanmaz –from_seqdeğeri kaydedilmişto_seq'e eşit olsa bile (birfullremovedtaşımaz, aksi halde silinen oteller yerinde kalırdı). - Asla geriye doğru değil: Belirleyici olan zincirin hedefidir, yani son sayfanın
to_seqdeğeri (more: false), ilk sayfanınki değil. Birfullzincirinin ilk sayfası çoğu zaman kaydedilmiş durumdan daha küçük birto_seqtaşır (örneğin410sonrasında: en eski dosyalar önce gelir) ve yine de bir geri adım değildir. Hedefi kaydedilmiş durumdan küçük olan, aynıepoch'a ait birfullzinciri veya daha eski birepoch'a ait birfull(epochzamana göre sıralı bir ULID'dir) reddedilir – gecikmeli teslim edilmiş eski bir paket önbelleği geri almaz.changesdurumuna boşluksuz bağlanmalıdır (from_seq= kaydedilmişto_seq). Başka bir kiracının veya kapsamınfull'ü (karıştırılmış anahtar) da reddedilir, geriye doğru kontrolden önce kapsam hatası olarak. - Reddedilen
full: Eski durum geçerli kalır, önbellek onunla hesaplamaya devam eder, ancak artık yeni bir şey çekmez. Bu kasıtlı olarak yüksek sesle olur – asla sessizce geri sıçramaz. Karıştırılmış anahtar söz konusu değilse ve teslimat gerçekten daha eski birepochüzerindeyse (örneğin saati geri kalan bir makinede yapılan bir geri yüklemeden sonra: yeniepochULID'si o zaman daha küçüktür) veya daha küçük birto_seqüzerindeyse, durumu bilinçli olarak sıfırlayın (referans alıcı:edf-empfaenger reset) ve yeni birfullçekin. Şüphe durumunda önce işletmeciye danışın. - Çekme sırasında okuma: Bir çekme uzun sürebilir (büyük zincir,
429beklemesi). Önbellekten fiyatlar bu sırada eski durumla, geçişten sonra ise yeni durumla çalışmaya devam eder; eski durumu ancak artık kimse onu okumuyorsa silin. Referans alıcı stok başına bir yazıcıya (pull,apply,reset) ve istenen sayıda okuyucuya (stand,rechne) izin verir.429için yanıt başına en fazla--max-warten, çekme başına toplam en fazla--max-warten-gesamtbekler, sonra iptal eder (durum değişmez). - Yeniden başlamak yerine tekrarlama: Kısa süreli hata veren bir sonraki sayfayı referans alıcı aynı parametrelerle üç kereye kadar çeker (10.2'deki kural); zincir başlangıcını tekrarlamaz.
- Önbellekten fiyat: Beyan edilen kurallarla EDF 5.1.6, ayrıca API'nin kuralları: aynı istek sınırları (Ek, aynı hata kodları; referans tarihi = Europe/Berlin'de bugün); oda ile bu oda kodunun en uygun fiyatlı teklifi, oda olmadan en uygun fiyatlı müsait oda, hiçbiri müsait değilse fiyatlandırılabilir en uygun fiyatlı oda ( Bölüm 3.1'deki gibi); pansiyon tipini sunmayan bir oda fiyatlandırılmaz.
- Beyan edilen kurallar: Her otel dosyası
SellingDataiçinde çocuk sıralamasını belirtir (ChildrenAgeOrder,Descending= önce en büyük çocuk: „1. çocuk“ kimdir, hangi çocuk boş bir tam ücret yerini doldurur),FullPayerDoesNotAffectBoardCharges/PersonType=C(tam ücret yerindeki bir çocuk tam temel fiyatı, pansiyon tipini ise çocuk tarifesiyle öder) veRounding Mode="Commercial" DecimalPlace="2" Scope="Person"(yolcu başına bir yuvarlama, Bölüm 1.4). Şemanın serbestlik bıraktığı yerlerde TourAPI şöyle hesaplar – önbellek de aynısını yapmalıdır, aksi halde sapar:MinCount/MaxCountçocukları kişi türü başına ilk çocuktan itibaren, yetişkinleri tam ücret ödeyenlerden sonraki ilk yetişkinden itibaren sayar; bir bebek bir kişi koşulunda („3 kişiden itibaren“) yalnızca oda onu doluluğa sayıyorsa sayılır (Infants/@ApplyToOccupancyMin,MaxveyaYes); eksik birExtraMaxApply1 anlamına gelir;Operator="AND"ile birden fazla tarih penceresi kesişim olarak geçerlidir; bir ücretsiz gecenin yanındaki yüzde ek ücret ve indirimleri yalnızca bağışlanmayan gecelere uygulanır; kişi başına sabit bir tutar (PS,PN) obje fiyatında da kişi başına etki eder; oda kalemleri (obje fiyatı, doldurulmamış tam ücret yeri) en büyük yolcuya aittir ve onunla birlikte yuvarlanır. - Pattern'den müsaitlik: Odanın
[checkIn, checkOut)geceleri boyunca minimum, 10.1'deki gibi; dosyanın belirtmediği bir gece kapalıdır (asla „hiçbir şey teslim edilmediği için açık“ değil)./v1/price'ınconfiguredalanının önbellekte karşılığı yoktur: kontenjanı olmayan bir oda orada00olarak yer alır. - Rezervasyondan önce canlı: Önbellek API'nin bir durum gerisinde olabilir; önbellekte
açık, bu arada kapatılmış veya dolmuş bir geceyi
/v1/bookreddeder (ERR_STOP_SALE,ERR_SOLD_OUT).
11. Sandbox: test anahtarları ve test rezervasyonları
Bir test anahtarı (tk_test_…) bir canlı anahtarın ikizidir: aynı tur operatörü, aynı
müşteri grubu, aynı yetkiler (dışa aktarım yetkisi, ileride arama profili) — çalışma zamanında canlı anahtardan
devralınır. Canlı anahtarla aynı verileri okur (oteller, fiyatlar, hedefler,
müsaitlik, EDF teslimatı), ancak rezervasyonlar sandbox'a düşer: asla
tur operatörüne değil, kontenjan yok, dışa aktarım yok, konsolun rezervasyon listesi yok. Böylece
rezervasyon, rezervasyon bilgisi, iptal, idempotency ve tekrarlama mantığı gerçek tekliflerle test edilebilir.
- Test anahtarını tur operatörü konsolda canlı anahtar için oluşturur (anahtar satırındaki „Test-Key“ düğmesi) ve kendi erişim paketiyle iletir. 30 gün geçerlidir (en fazla 90), erişim başına en fazla 5 aktif test anahtarı.
- Canlı anahtar askıya alınmışsa veya test anahtarının süresi dolmuşsa:
401 ERR_UNAUTHORIZED. Müşteri grubu devre dışı: canlıdaki gibi403 ERR_KEY_GROUP_INACTIVE. Canlı anahtar yenilendikten sonra test anahtarı yeni canlı anahtarla çalışmaya devam eder; asla canlı anahtarından daha geç sona ermez. - Tur operatörü izin verdiyse test anahtarını iş ortağı portalında kendiniz de verebilirsiniz (7, 30 veya 90 gün).
- Mod için belirleyici olan anahtarın öneki değil, tur operatöründeki eşleştirmedir.
11.1 İşaretleme ve karıştırmaya karşı koruma
Kabul edilen bir anahtara verilen her yanıt X-TourAPI-Mode: test veya
live header'ını taşır (header adlarını HTTP'de olağan şekilde büyük/küçük harf ayrımı
yapmadan karşılaştırın: sunucu X-Tourapi-Mode yazar). Bir test anahtarının rezervasyon, rezervasyon bilgisi ve iptal yanıtları ayrıca
"sandbox": true alanını taşır, referans SB- ile başlar (canlıda TA-). Test anahtarıyla okuma
canlı anahtarla aynı yanıtı verir:
### sandbox-preis
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}]}
}Test ortamları (CI, ajanlar, geliştirici bilgisayarları) X-TourAPI-Require-Mode:
test header'ını gönderir. Bu durumda bir canlı anahtar gelirse API her isteği reddeder ve hiçbir şey yürütmez – böylece
yanlışlıkla kullanılan bir canlı anahtar rezervasyon yapamaz (kontrol istemcide değil,
sunucudadır). X-TourAPI-Require-Mode: live tersine bir canlı anahtar gerektirir; başka bir değer
400 ERR_BAD_REQUEST'tir.
### sandbox-live-key-in-testumgebung
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"
}{"errorCode": "ERR_MODE_MISMATCH", "message": "X-TourAPI-Require-Mode: test verlangt, der API-Key ist ein live-Key — nichts ausgefuehrt"}11.2 Test rezervasyonu, rezervasyon bilgisi, iptal
Test anahtarıyla /v1/book, canlıdakiyle aynı kontrollerden aynı sırayla geçer
(alanlar, tekrar, otel, referans tarihi ve sınırlar, satış kuralları, priceCheck,
müsaitlik) ve aynı hata kodlarını verir. Müsaitlik kontrol edilir, ancak
tüketilmez:
### sandbox-buchen
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
}
}{"booked": true, "alreadyBooked": false, "reference": "{{sandboxRef}}", "correlationId": "{{*}}", "sandbox": true}### sandbox-buchung-lesen
GET {{baseUrl}}/v1/booking?ref={{sandboxRef}}
X-Api-Key: {{testKey}}{"reference": "{{sandboxRef}}", "customerReference": "TEST-4711", "hotel": "TEST-HOTEL-BASE", "room": "DZ",
"checkIn": "{{D2}}", "checkOut": "{{D4}}", "quantity": 1, "status": "confirmed",
"bookedAt": "{{*}}", "updatedAt": "{{*}}", "totalCents": 18000, "currency": "EUR", "board": "RO", "sandbox": true}Test ve canlı dünya ayrıdır: Bir test anahtarı yalnızca test rezervasyonlarını görür ve iptal eder, bir
canlı anahtar yalnızca gerçek olanları. Aynı idemKey her iki dünyada birbirinden bağımsız olarak rezervasyon yapar.
### sandbox-live-key-sieht-testbuchung-nicht
GET {{baseUrl}}/v1/booking?ref={{sandboxRef}}
X-Api-Key: {{apiKey}}{"errorCode": "ERR_BOOKING_NOT_FOUND", "message": "keine Buchung zu '{{sandboxRef}}'"}### sandbox-stornieren
POST {{baseUrl}}/v1/cancel
Content-Type: application/json
X-Api-Key: {{testKey}}
{"idemKey": "BEISPIEL-0001"}{"released": true, "alreadyReleased": false, "sandbox": true}- Test rezervasyonları oluşturulmalarından 30 gün sonra silinir. Erişim başına en fazla 5.000 açık (iptal
edilmemiş) test rezervasyonu, üzerinde
422 ERR_SANDBOX_LIMIT. - Bir test anahtarının çağrılarını (metot, yol, durum,
errorCode, süre, istek ve yanıt) TourAPI 7 gün boyunca kaydeder, böylece tur operatörü hata ayıklamada yardımcı olabilir. Bu nedenle: test rezervasyonlarında test isimleri kullanın. - Test anahtarıyla EDF teslimatı: çağrılar (
full,changes) ve onaylar (ack) yalnızca test çağrılarının bu kaydında yer alır, tur operatörünün teslimat kaydında asla yer almaz – teslimatın health durumunda alım veya işleme olarak sayılmazlar.
11.3 Senaryolar: hata durumlarını zorlama
X-TourAPI-Sandbox-Scenario header'ı ile bir test anahtarı bir hata durumunu zorlar –
tekrarlama mantığını test etmek için (Bölüm 8 ve 9). Bir canlı anahtarla, bilinmeyen bir adla
veya senaryonun etkisiz olduğu bir endpoint'te: 422 ERR_SCENARIO_NOT_ALLOWED.
- Senaryo
booking_busy- Endpoint'ler
/v1/book,/v1/cancel- Etki
idemKeyve endpoint başına ilk deneme (rezervasyon ve iptal ayrı sayılır):Retry-After: 1ile503 ERR_BOOKING_BUSY, hiçbir şey rezerve veya iptal edilmez; aynıidemKeyile tekrar başarılı olur
- Senaryo
price_drift- Endpoint'ler
priceCheckile/v1/book- Etki
idemKeybaşına ilk deneme:409 ERR_PRICE_DRIFT; fiyatın kendisi değişmez (messagegüncel ve beklenen fiyatı verir, ikisi aynıdır); yeni fiyatı alın, yeniden rezervasyon yapın
- Senaryo
sold_out- Endpoint'ler
/v1/book- Etki
- her zaman
422 ERR_SOLD_OUT(diğer tüm kontrollerden sonra)
- Senaryo
rate_limited- Endpoint'ler
- tümü
- Etki
- test anahtarı ve endpoint başına ilk istek:
Retry-After: 1ile429 ERR_RATE_LIMITED
- Senaryo
search_busy- Endpoint'ler
/v1/search- Etki
- test anahtarı başına ilk istek:
Retry-After: 1ile429 ERR_SEARCH_BUSY
- Senaryo
price_timeout- Endpoint'ler
/v1/price,/v1/prices- Etki
- test anahtarı ve endpoint başına ilk istek:
503 ERR_PRICE_TIMEOUT
„İlk istek“ 10 dakika geçerlidir; bu süre içindeki her tekrar normal şekilde işlenir. Bellek API'nin her düğümünde ayrı tutulur.
### sandbox-szenario-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"
}{"errorCode": "ERR_BOOKING_BUSY", "message": "Buchung/Storno kam wegen gleichzeitiger Vorgaenge am selben Hotel nicht durch; nichts geaendert — mit demselben idemKey wiederholen (Sandbox-Szenario booking_busy)"}### sandbox-szenario-busy-wiederholt
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"
}{"booked": true, "alreadyBooked": false, "reference": "{{*}}", "correlationId": "{{*}}", "sandbox": true}### sandbox-szenario-live-key
GET {{baseUrl}}/v1/destinations
X-Api-Key: {{apiKey}}
X-TourAPI-Sandbox-Scenario: rate_limited{"errorCode": "ERR_SCENARIO_NOT_ALLOWED", "message": "X-TourAPI-Sandbox-Scenario: nur mit einem Test-Key (Sandbox)"}11.4 Test anahtarlarının sınırları
Bir erişimin tüm test anahtarları tek bir kotayı paylaşır: saniyede 20 istek, burst 40 (bunun yanında
canlı anahtarın sınırı etkilenmez). Bir tur operatörünün test anahtarları en fazla 2
eşzamanlı arama kullanır. EDF teslimatının döngüsü (full 1/saat, yeni changes zinciri 1/dk)
test anahtarı başına değil, erişim başına geçerlidir.
11.5 Sandbox'ın kanıtlamadıkları
- Kontenjan ve son oda için yarış: Test rezervasyonları hiçbir şey tüketmez. Bir test rezervasyonu, canlıda başkasının daha hızlı olduğu yerde başarılı olabilir.
- Rezervasyondan sonra tur operatöründeki süreçler (onay, değişiklik, fatura).
- Canlı yük altındaki davranış (ayrı, daha küçük kota, bkz. 11.4).
11.6 Yapay zeka ajanları: portaldaki MCP sunucusu
Portal, /mcp adresinde bir MCP sunucusu sunar (Model Context Protocol, “Streamable HTTP”
aktarımı, durumsuz, yalnızca araçlar). Claude Code, Codex veya Antigravity gibi bir yapay zeka
ajanı, HTTP kodu yazmak yerine API'yi bu araçlar üzerinden çağırır. Her araç, MCP isteğinin
anahtarıyla (X-Api-Key veya Authorization: Bearer) ve X-TourAPI-Require-Mode: test ile
yapılan tam olarak bir /v1 çağrısıdır – davranış, sınırlar, yalıtım ve hata kodları
API'ninkilerdir. Yalnızca test anahtarları: canlı anahtar ERR_MODE_MISMATCH (403) alır,
hiçbir şey yürütülmez. Portal hiçbir anahtarı saklamaz.
| Araç | Çağrı | Argümanlar |
|---|---|---|
list_destinations | GET /v1/destinations | yok |
search_hotels | POST /v1/search | istek gövdesi; sayfalar cursor ile |
price_offer | POST /v1/price | istek gövdesi |
price_all_rooms | POST /v1/prices | istek gövdesi |
sandbox_book | POST /v1/book | istek gövdesi, idemKey zorunlu |
get_booking | GET /v1/booking | ref |
sandbox_cancel | POST /v1/cancel | istek gövdesi |
get_limits | GET /v1/limits | yok |
open_search | POST /v1/search/open | istek gövdesi |
open_search_dates | POST /v1/search/open/dates | istek gövdesi |
hotel_details | GET /v1/content/hotels/{code} | code, lang |
İstek gövdesi olan araçlar argümanlarını değiştirmeden JSON gövdesi olarak API'ye iletir (şema =
uç noktanın OpenAPI tanımı). Diğerleri yalnızca listelenen argümanları alır; başka bir argüman
ERR_UNKNOWN_FIELD, geçersiz bir değer ERR_BAD_REQUEST verir – API çağrısı yapılmadan.
hotel_details yalnızca içerik yetkisiyle. tools/list, isteğin anahtarıyla GET /v1/limits
sorgular ve hotel_details aracını yalnızca content.allowed: true ise listeler (içerik API'siyle
aynı kural, 4c); anahtar yoksa listede yer almaz. Yine de çağrılırsa API ERR_CONTENT_NOT_ALLOWED
(403) döndürür. API bu kontrolde anahtarı reddederse (ör. canlı anahtar için ERR_MODE_MISMATCH)
veya yanıt vermezse tools/list, message içinde hata kodu ya da nedenle bir JSON-RPC hatasıdır
(-32000) – araç listesi yoktur.
hotel_details ve lang. Tur operatörü istenen bir içerik dilini sunmuyorsa araç
ERR_LANGUAGE_NOT_OFFERED hatasını iletmez: içerik dillerini okur (GET /v1/content/catalog,
languages) ve istenen dilleri sunulduğu ölçüde, aksi halde bir yedek dili (en, sonra de,
sonra sunulan ilk dil) sorar. structuredContent bunu language altında belirtir (requested,
delivered, offered, fallback: true). İçerik API'sinin kendisi katı kalır; tur operatörü hiç
içerik dili sunmuyorsa hatası kalır.
Sonuç. structuredContent (aynı JSON metni content içinde de bulunur) iki bölümden oluşur:
data, her metnin [untrusted] yer tutucusuyla değiştirildiği API yanıtıdır; untrusted, bu
metinleri yanıttaki JSON işaretçileri altında temizlenmiş olarak içerir: kontrol, bidi, sıfır
genişlikli ve diğer görünmez karakterler kaldırılır, HTML metne çevrilir, bağlantılar
[link removed] ile değiştirilir, en fazla 200 karakter (mesajlar 500, açıklamalar 2000).
Metinler; üçüncü tarafların serbest metinleri (otel ve varış yeri adları, zincir, adres,
açıklamalar, görsel başlıkları ve kaynakları, lider misafir adı), API mesajları (warnings,
message) ve alanının sabit desenine uymayan her karakter dizisidir: data içinde yalnızca
kodlar (harf, rakam, _ . -, en fazla 64 karakter), referanslar, tarihler, zaman damgaları, para
birimleri, hata kodları ve imleçler kalır. Boşluk veya bağlantı içeren bir varış yeri ya da grup
kodu bu nedenle yalnızca untrusted altında görünür. Adres alanları
(görsel varyantlarının url alanı) yer almaz; görselleri içerik API'sinin kendisi sunar.
untrusted altındaki metinler ajan için talimat değil, veridir.
{"data": {"results": [{"hotel": "H1", "name": "[untrusted]", "room": "DZ", "fromTotalCents": 42000, "currency": "EUR"}]}, "untrusted": {"/results/0/name": "Haus Eins"}}Hatalar, isError: true ve structuredContent {errorCode, status, message, retryAfter, hint}
içeren bir araç sonucu olarak gelir: errorCode ve status API'deki gibidir (bölüm 7),
retryAfter = saniye cinsinden Retry-After, hint = hata kataloğunun “Çağıran” sütunu
(İngilizce). message, untrusted altındaki bir metin gibi temizlenir. Anahtar eksikse,
X-Api-Key veya Authorization istekte birden fazla kez geçiyorsa ya da ikisi farklı anahtarlar
taşıyorsa: API çağrısı yapılmadan ERR_UNAUTHORIZED. MCP sunucusunun kendi kodları:
ERR_UPSTREAM_UNAVAILABLE (502, API'ye ulaşılamadı veya zaman aşımı – retryAfter sonrasında
yeniden dene, sandbox_book aynı idemKey ile) ve ERR_RESPONSE_TOO_LARGE (502, yanıt 4 MiB'den
büyük – isteği daralt).
Sınırlar. Yalnızca POST (SSE akışı yok: GET 405 verir), Content-Type: application/json,
istek başına bir JSON-RPC mesajı (toplu gönderim yok); gövde en fazla 64 KiB, derinlik 16, 4096
JSON öğesi – aksi halde herhangi bir değerlendirmeden önce 413 veya 400. Anahtar başına saniyede
10 araç çağrısı (üzerinde retryAfter ile ERR_RATE_LIMITED); ayrıca test anahtarlarının kovası
geçerlidir (11.4). Yabancı Origin içeren bir istek 403 alır (tarayıcıdaki web sayfalarına karşı
koruma); çerez yok, CORS yok. Protokol sürümleri 2025-03-26, 2025-06-18 ve 2025-11-25.
Kurulum. Test anahtarını TOURAPI_API_KEY ortam değişkeni olarak ayarlayın (kendi kodunuzdakiyle aynı; tek
değişken yeterli); yapılandırmaya yalnızca ona yapılan referans girer. Claude Code, projede .mcp.json dosyası:
{"mcpServers": {"tourapi": {"type": "http", "url": "https://portal.example.de/mcp", "headers": {"X-Api-Key": "${TOURAPI_API_KEY}"}}}}Codex (anahtar, ortam değişkeninden bearer token olarak gönderilir):
codex mcp add tourapi --url https://portal.example.de/mcp --bearer-token-env-var TOURAPI_API_KEYAntigravity headers içine ortam değişkeni doldurmaz; mcp-remote köprüsü anahtarı ortamdan
okur (mcp_config.json içindeki girdi; anahtarı denetlenmemiş bir sürüm almasın diye köprü
sürümü sabittir):
{"mcpServers": {"tourapi": {"command": "npx", "args": ["-y", "mcp-remote@0.14.3", "https://portal.example.de/mcp", "--header", "X-Api-Key:${TOURAPI_API_KEY}"]}}}Portaldaki “Yapay zeka ajanları” sayfası aynı girdileri portalınızın adresiyle gösterir.
12. Otel içerikleri: /v1/content/*
Content API, tur operatörünün otel içeriklerini alıcıların web siteleri ve katalogları için sunar: ana veriler (tesis türü, zincir, adres), konum (koordinatlar), kategoriler, bilgiler, metinler, görseller ve olanaklar. Fiyat ve rezervasyonun yanında ayrı bir yoldur: içerikler hiçbir fiyatı ve müsaitliği değiştirmez.
| Rota | Amaç |
|---|---|
GET /v1/content/hotels | Anahtarın otellerinin dizini, code'a göre artan, sayfalı |
GET /v1/content/hotels/{code} | Bir otelin içeriği (ETag, If-None-Match → 304) |
GET /v1/content/changes?since=… | Bir durumdan bu yana değişiklikler, kaydedildikleri sırayla |
GET /v1/content/catalog | Etiketli kataloglar (tesis türleri, kategori ölçekleri, metin ve görsel türleri, olanaklar) |
12.1 Erişim ve kapsam
- Content API yalnızca ikisi de geçerliyse yanıt verir: platform işletmecisi içerikleri tur
operatörü için etkinleştirmiştir ve anahtar içerik yetkisini taşır (tur operatörü
yöneticisi API erişimi altında verir, varsayılan kapalı). Aksi halde
403 ERR_CONTENT_NOT_ALLOWED. Bir test anahtarı canlı anahtarının yetkisine sahiptir ve aynı içerikleri okur. - Platform işletmecisinin test ortamı olarak yürüttüğü bir tur operatörüne yalnızca bunun için
kurulan kurulum hizmet verir. Diğer her yerde etkin değil sayılır: aynı yanıt
403 ERR_CONTENT_NOT_ALLOWED. - Bir anahtarın hangi otelleri gördüğünü
/v1/destinations'daki gibi anahtar belirler (1.1): müşteri grubu olmadan ve fiyat grubuyla tur operatörünün tüm otelleri, kontenjan grubuyla yalnızca tahsisi olan oteller – müsaitlikten bağımsız. Diğer her otel404 ERR_HOTEL_NOT_FOUND'dur. - Yalnızca tur operatörünün içerik dillerindeki görünür metinler ve görünür, tamamen işlenmiş görseller sunulur. Otelin iletişim bilgileri (telefon, e-posta, web) Content API'de yoktur, boş alan olarak bile.
- Görseller herkese açık, tahmin edilemeyen adreslerde bulunur
(
<base>/m/<key>/<size>.jpg, anahtarsız alınabilir, 1 gün önbelleğe alınabilir). Her görselin yanındacreditvardır;attributionRequired: trueise atıf görselin yanında gösterilmelidir. - Anahtarlar tarayıcı koduna ait değildir (1.1): web sitesi Content API'yi sunucuda okur, tarayıcıya yalnızca görsel adresleri gider.
12.2 Dizin
### inhalt-verzeichnis
GET {{baseUrl}}/v1/content/hotels?pageSize=2
X-Api-Key: {{apiKey}}{
"hotels": [
{"code": "TEST-HOTEL-ALTAKTION", "name": "TEST Altaktion Teneriffa", "destination": "TFS", "contentVersion": 0, "websiteReady": false, "missing": ["general_text", "geo", "category", "images", "amenities"]},
{
"code": "TEST-HOTEL-BASE",
"name": "TEST Basis Palma",
"destination": "PMI",
"contentVersion": "{{*}}",
"updatedAt": "{{*}}",
"category": {"kind": "official", "scheme": "stars", "value": 4, "superior": true},
"geo": {"lat": 39.565, "lon": 2.627, "precision": "address"},
"websiteReady": false,
"missing": ["images", "amenities"]
}
],
"nextCursor": "{{*}}",
"feedToken": "{{*}}",
"scopeHash": "{{*}}"
}pageSize1–1000 (varsayılan 500). Sonraki sayfacursor=<nextCursor>ile alınır;nextCursoryoksa dizin eksiksizdir.contentVersionbir otel için sunulan içeriğin her değişikliğini sayar;0= henüz içerik yok (o zamanupdatedAtyoktur).categoryresmi ülke kategorisidir,geokonum – ikisi de yalnızca bakımı yapılmışsa.websiteReadyvemissingbir otelin içeriğindeki gibi (12.3).feedToken,/v1/content/changes'in devam ettiği durumdur. Bir dizin geçişinin tüm sayfaları aynı durumu taşır (ilk sayfanınkini).scopeHash, anahtarın otel kümesi değişir değişmez değişir (yeni veya silinmiş otel, tahsis eklendi veya kaldırıldı). Bu akışta yer almaz: o zaman dizini yeniden alın.cursor,feedTokenvenextopaktır ve anahtara bağlıdır: başka bir anahtarla, değiştirilmiş olarak veya sunucunun anahtar değişikliğinden sonra422 ERR_BAD_CURSOR.
### inhalt-verzeichnis-weiter
GET {{baseUrl}}/v1/content/hotels?pageSize=2&cursor={{inhaltCursor}}
X-Api-Key: {{apiKey}}{
"hotels": [
{"code": "TEST-HOTEL-CLOSED", "name": "TEST Geschlossen Mahon", "destination": "MAH", "contentVersion": 0, "websiteReady": false, "missing": ["general_text", "geo", "category", "images", "amenities"]},
{
"code": "TEST-HOTEL-DISCOUNT",
"name": "TEST Rabatt Palma",
"destination": "PMI",
"contentVersion": "{{*}}",
"updatedAt": "{{*}}",
"category": {"kind": "official", "scheme": "stars", "value": 4},
"geo": {"lat": 39.5696, "lon": 2.6502, "precision": "locality"},
"websiteReady": false,
"missing": ["general_text", "images", "amenities"]
}
],
"nextCursor": "{{*}}",
"feedToken": "{{*}}",
"scopeHash": "{{*}}"
}12.3 Bir otelin içeriği
### inhalt-hotel
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=de,tr
X-Api-Key: {{apiKey}}{
"code": "TEST-HOTEL-BASE",
"name": "TEST Basis Palma",
"destination": "PMI",
"contentVersion": "{{*}}",
"updatedAt": "{{*}}",
"accommodationType": "HOTEL",
"categories": [{"kind": "official", "scheme": "stars", "value": 4, "superior": true}],
"address": {"street": "Passeig Marítim 12", "postalCode": "07014", "city": "Palma", "region": "Mallorca", "country": "ES"},
"geo": {"lat": 39.565, "lon": 2.627, "precision": "address"},
"facts": {"rooms": 120, "checkInFrom": "14:00", "checkOutUntil": "11:00"},
"texts": [
{"type": "GENERAL", "lang": "de", "html": "<p>TEST-Hotel am Strand mit <b>Pool</b> und Garten.</p>\n<p>TEST-Lage: ruhige Bucht.</p>", "updatedAt": "{{*}}"},
{"type": "GENERAL", "lang": "de", "fallbackFrom": "tr", "html": "<p>TEST-Hotel am Strand mit <b>Pool</b> und Garten.</p>\n<p>TEST-Lage: ruhige Bucht.</p>", "updatedAt": "{{*}}"}
],
"media": [],
"amenities": [
{"code": "WIFI_ROOM", "available": true, "charge": "included"},
{"code": "SPA", "available": false},
{"code": "DIST_AIRPORT", "available": true, "distanceM": 12000, "ref": "PMI"}
],
"websiteReady": false,
"missing": ["images", "amenities"]
}- Diller:
langolmadan tur operatörünün tüm içerik dillerindeki tüm metinler gelir.langile (1–5 dil, ISO 639-1 küçük harf, virgülle ayrılmış) her metin türü ve istenen dil için tam olarak bir kayıt gelir. Metin bu dilde yoksa tur operatörünün varsayılan dili, ardından İngilizce devreye girer; kayıt o zaman istenen dilifallbackFromolarak taşır (burada: Türkçe metin yok, Almanca gelir). Orada da yoksa kayıt eksik kalır. Görsellerin başlıkları (titles) ve alternatif metinleri (alts) aynı kurala uyar. Tur operatörünün sunmadığı bir dil:422 ERR_LANGUAGE_NOT_OFFERED(etkin dillerwarningsiçindedir). htmlyalnızca özniteliksizp,br,b,strong,i,em,ul,ol,liiçerir.machineTranslated: truebir makine çevirisini işaretler.categories:kindofficial(ülke kategorisi) veyaoperator(tur operatörünün derecelendirmesi),schemestarsveyakeys,valueyarım adımlarla 1–5; "4 Superior"value: 4, superior: true'dur, asla 4,5 değil.geo.precision:address,street,localityveyaunknown.mediagösterim sırasıyla,order: 1ana görseldir. Her görsel için oluşturulan genişliklerlevariants(w320ilew2048arası, asla orijinalden geniş değil), her biri genişlik, yükseklik, bayt veurlile;focus(yüzde olarak x, y) kendi kırpmalarınız için görselin en önemli noktasıdır.id, görsel otelde kaldığı sürece sabittir.amenities: katalogdan kodlu olanaklar (12.5).available: falseaçıkça mevcut değil demektir; eksik bir olanak bilinmiyordur. Olanağa görecount,distanceM,areaM2,ref(mesafe için havalimanı kodu) ve ücretli olabilen olanaklardacharge(included,extra,unknown) ile.name,destinationvegiataCodeotelin sözleşmesinden gelir. Bunlardan biri değişirse otel akışta yer alır (12.4,reason: contract) ve bundan sonra detay ile dizin yeni değeri döndürür.websiteReadyvemissing: "web sitesine hazır" olgunluk düzeyi – tur operatörünün bir web sitesi için yeterli içerik girip girmediği. Yalnızca bir göstergedir; ne satışı ne de sunumu değiştirir.missingeksik ölçütleri sabit sırayla listeler, boş = web sitesine hazır:general_text(operatörün varsayılan dilinde genel metin),geo(konum),category(kategori veya tesis türü),images(ana görsel dahil en az 5 sunulan görsel),amenities(açıkça "mevcut değil" dahil en az 10 girilmiş özellik). Değerlendirme yalnızca içerikle değişir (yenicontentVersion); operatörün konsolu aynısını gösterir.missingiçindeki bilinmeyen değerleri yok sayın (ölçüt eklenebilir). Dizinde de her iki alan bulunur.
Her yanıt bir ETag taşır. İçerik, dil seçimi ve gösterimle birlikte değişir.
If-None-Match ile hiçbir şey değişmediği sürece gövdesiz 304 gelir:
### inhalt-hotel-unveraendert
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=de,tr
X-Api-Key: {{apiKey}}
If-None-Match: {{inhaltEtag}}lang olmadan tüm içerik dilleri (burada en makine çevirisi olarak):
### inhalt-hotel-alle-sprachen
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE
X-Api-Key: {{apiKey}}{
"code": "TEST-HOTEL-BASE",
"name": "TEST Basis Palma",
"destination": "PMI",
"contentVersion": "{{*}}",
"updatedAt": "{{*}}",
"accommodationType": "HOTEL",
"categories": "{{*}}",
"address": "{{*}}",
"geo": "{{*}}",
"facts": "{{*}}",
"texts": [
{"type": "GENERAL", "lang": "de", "html": "{{*}}", "updatedAt": "{{*}}"},
{"type": "GENERAL", "lang": "en", "html": "<p>TEST hotel on the beach with a <b>pool</b> and garden.</p>\n<p>TEST location: quiet bay.</p>", "machineTranslated": true, "updatedAt": "{{*}}"}
],
"media": [],
"amenities": "{{*}}",
"websiteReady": false,
"missing": ["images", "amenities"]
}12.4 Değişiklikler
### inhalt-aenderungen
GET {{baseUrl}}/v1/content/changes?since={{feedToken}}
X-Api-Key: {{apiKey}}{"changes": [], "next": "{{*}}", "more": false, "scopeHash": "{{*}}"}since, dizininfeedToken'ı veya önceki yanıtınnextdeğeridir (zorunlu, aksi halde400 ERR_BAD_REQUEST).pageSize1–1000 (varsayılan 500).- Her kayıtta
code,change(upsert= içerik değişti, yeniden alın;removed= otel silindi),upsertiçin güncelcontentVersionve isteğe bağlıreason(languages= tur operatörünün içerik dilleri değişti,media_ready= bir görsel tamamen işlendi,contract=name,destinationveyagiataCodesözleşmeyle değişti,removediçindeleted). Bilinmeyen değerleri yok sayın. - Değişikliklerin kaydedildiği sırayla, boşluksuz; bir otel her sayfada en fazla bir kez yer
alır (son durumuyla).
more: true= hemennextile okumaya devam edin. - Yalnızca anahtarın otelleri. Otel kümesinin değişmesi akışta değil,
scopeHash'te yer alır. - Akış 30 gün geriye gider. Daha eski bir durum:
410 ERR_CONTENT_CURSOR_EXPIRED– o zaman dizini yeniden alın ve onunfeedToken'ı ile devam edin.
12.5 Katalog
### inhalt-katalog
GET {{baseUrl}}/v1/content/catalog?lang=de
X-Api-Key: {{apiKey}}{
"version": "2026.1",
"languages": ["de", "en", "tr"],
"defaultLanguage": "de",
"labelLanguages": ["de"],
"accommodationTypes": "{{*}}",
"categorySchemes": [{"code": "sterne", "sort": 1, "labels": {"de": "Sterne"}}, {"code": "schluessel", "sort": 2, "labels": {"de": "Schlüssel"}}],
"textTypes": "{{*}}",
"mediaTypes": "{{*}}",
"amenityGroups": "{{*}}",
"amenities": "{{*}}"
}languagestur operatörünün içerik dilleridir,defaultLanguagevarsayılan dilidir.langetiket dillerini seçer (de,en,tr;langolmadan tümü).- Her olanak için
group,valueType(flag,anzahl,meter,flaeche_m2,meter_mit_bezug),unitvechargeable. Bir kod asla yeniden yorumlanmaz;locked: truekaldırıldı demektir (okunabilir kalır).versionher yeni katalogla değişir; katalog birETagtaşır.
12.6 Alıcılar için eşitleme
- İlk yükleme: dizini sayfa sayfa alın,
feedTokenvescopeHash'i saklayın, her otel için içeriği alın veETag'i kaydedin. - Sürekli (aşağı yukarı birkaç dakikada bir):
changes?since=<token>(ilk çağrıdafeedToken, sonrasında en son saklanannext), değişen otelleri yeniden alın,removedolanları silin,next'i saklayın.scopeHashdeğişirse: hemen 3. adım. - Günlük ve
410durumunda: dizini yeniden alın ve kendi verilerinizle eşitleyin (eksik otelleri silin, yenilerini alın,contentVersion'ı karşılaştırın). - İçerikleri her zaman
If-None-Matchile alın.
Erişim ve kapsam hataları:
### inhalt-ohne-recht
GET {{baseUrl}}/v1/content/hotels
X-Api-Key: {{poolKey}}{"errorCode": "ERR_CONTENT_NOT_ALLOWED", "message": "dieser API-Key hat kein Inhalts-Recht — der Veranstalter-Admin schaltet es unter API-Zugang frei"}### inhalt-nicht-im-verzeichnis
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-DISCOUNT
X-Api-Key: {{partnerKey}}{"errorCode": "ERR_HOTEL_NOT_FOUND", "message": "Hotel 'TEST-HOTEL-DISCOUNT' nicht im Verzeichnis dieses API-Keys"}### inhalt-sprache-nicht-angeboten
GET {{baseUrl}}/v1/content/hotels/TEST-HOTEL-BASE?lang=fr
X-Api-Key: {{apiKey}}{"errorCode": "ERR_LANGUAGE_NOT_OFFERED", "message": "lang: 'fr' ist keine Inhaltssprache dieses Veranstalters (ISO 639-1, klein)", "warnings": ["aktive Inhaltssprachen: de, en, tr (Standard de)"]}### inhalt-stand-fremder-key
GET {{baseUrl}}/v1/content/changes?since={{feedToken}}
X-Api-Key: {{partnerKey}}{"errorCode": "ERR_BAD_CURSOR", "message": "since: unlesbar, von einem anderen API-Key oder nicht von diesem Server — den Wert der Vorseite unveraendert zurueckgeben, sonst neu beginnen"}13. Planlananlar ve sınırlar
Planlananlar: /v1 içinde yalnızca eklemeli değişiklikler yapılır (bölüm 1.9); her
değişiklik tarihiyle birlikte değişiklik günlüğünde yer alır. Şu anda mevcut bir entegrasyonun
uyarlanmasını gerektiren duyurulmuş bir değişiklik yoktur.
Sınırlar: Sayısal değerler (boyutlar, hızlar, zaman sınırları) "Bir bakışta sınırlar" ekindedir; sandbox'ın kapsamadıkları 11.5'tedir.
Ek: Bir bakışta sınırlar
- Ne
- İstek başına body
- Değer
- 1 MiB
- Ne
- Konaklama başına gece
- Değer
- 1–30
- Ne
- Giriş
- Değer
- referans tarihinden referans tarihi + 732 güne kadar
- Ne
- İstek başına yolcu, yaş
- Değer
- 1–20, 0–120
- Ne
- Rezervasyon başına oda (
quantity) - Değer
- 1–1.000.000
- Ne
idemKey,reference- Değer
- 128 karakter (daha uzunu:
422 ERR_VALIDATION)
- Ne
leadPaxName- Değer
- 255 karakter (daha uzunu:
422 ERR_VALIDATION)
- Ne
metadata.correlationId- Değer
- 64 karakter (daha uzunu:
422 ERR_VALIDATION)
- Ne
- Anahtar başına hız
- Değer
- 200/sn, burst 400
- Ne
- Erişim başına test anahtarları
- Değer
- en fazla 5, 90 güne kadar geçerli; toplam 20/sn, burst 40; tur operatörü başına 2 eşzamanlı arama
- Ne
- Test rezervasyonları
- Değer
- erişim başına 5.000 açık, oluşturulduktan 30 gün sonra silinir; test çağrılarının kaydı 7 gün
- Ne
- Arama süre sınırı
- Değer
- 10 sn
- Ne
- Arama sayfası
- Değer
- varsayılan 50, en fazla 100 otel
- Ne
- Açık arama
- Değer
- anahtar başına arama profiline göre (pencere, süreler, hedefler, sayfa, zaman bütçesi, istek hızı; tarih matrisi: pencere ve hücreler),
GET /v1/limitsile alınabilir; belirtilmezse sayfa 20; cursor 15 dk
- Ne
- Bağlantı
- Değer
- 15 sn okuma, 15 sn yazma
- Ne
- Anahtar başına EDF teslimatı
- Değer
full1/saat, yenichangeszinciri 1/dk, sonraki sayfalar/onaylar 5/sn (burst 50); paket yanıtları 10 dakikaya kadar yazabilir
- Ne
- Content API
- Değer
- dizin ve akış sayfası 1–1000 (varsayılan 500),
lang1–5 dil, akış 30 gün