Business Platform
TravelShop

API Referansı

TravelShop Booking API

10.000'den fazla turu arayın, canlı fiyat ve müsaitlik çekin, kendi platformunuzdan rezervasyon oluşturun. Bu referans herkese açıktır — başvurmadan önce okuyun.

Başlarken

API, HTTPS üzerinden JSON dönen düz bir REST API’dir; erişiminiz onaylandıktan sonra kendiniz ürettiğiniz tek bir API key ile doğrulanır. Aşağıdaki örneklerde {BASE_URL} yer tutucu olarak kullanılıyor — kendi base URL’iniz geliştirici panelinde, key’inizin yanında yazar.

  1. 1

    Başvurun

    Platformunuzu anlatın. Her başvuruyu elle inceliyoruz, genellikle 1–2 iş günü içinde.

  2. 2

    Key’inizi üretin

    Onaydan sonra geliştirici panelinden API key’inizi oluşturun ve API’yi çağıracak sunucuların IP adreslerini kaydedin. Key yalnızca bir kez gösterilir.

  3. 3

    API’yi çağırın

    Key’i her istekte X-API-Key header’ı olarak gönderin. Tüm el sıkışma bundan ibaret.

Kimlik doğrulama

Key’inizi her istekte X-API-Key header’ında gönderin. OAuth akışı, token değişimi ve son kullanma tarihi yok — key’i yenileyene ya da iptal edene kadar geçerli kalır.

curl
curl -X GET '{BASE_URL}/b2b/api/apiv2/b2c/tours/search?term=cappadocia&page_size=5' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Accept: application/json'
node
const res = await fetch(
  '{BASE_URL}/b2b/api/apiv2/b2c/tours/search',
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.TSB_API_KEY,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ term: 'cappadocia', page_size: 5 }),
  },
)

const data = await res.json()
API’yi sunucunuzdan çağırın, asla tarayıcı kodundan — tarayıcıya gönderilen key artık herkese açıktır. Key’inizin yalnızca hash’lenmiş bir kopyasını sakladığımız için key tam olarak bir kez, oluşturduğunuz anda gösterilir. Kaybettiyseniz yenisini üretin; eskisi o anda geçersiz olur.

IP izin listesi

Partner endpoint’leri yalnızca kaydettiğiniz sunucu IP adreslerinden gelen istekleri kabul eder. Erişiminiz onaylandıktan sonra sunucularınızın giden istekler için kullandığı genel (public) IP adreslerini geliştirici panelinden ekleyin — varsayılan olarak en fazla 3 adres.

  • Tek tek IPv4 veya IPv6 adresleri kaydedin. Adres aralıkları, özel (private) ya da ayrılmış (reserved) adresler ve Cloudflare’e ait adresler kabul edilmez.
  • Sitenizin IP’sini değil, sunucunuzun istek gönderdiği adresi kullanın. Siteniz Cloudflare arkasındaysa o adres Cloudflare’e aittir ve kaydedilemez.
  • Sunucunuzda IPv6 varsa istekler IPv6 üzerinden çıkabilir. O adresi de kaydedin ya da HTTP istemcinizi IPv4 kullanmaya zorlayın. İki adresi de görmek için aşağıdaki komutları doğrudan sunucuda çalıştırın.
  • Değişiklikler yaklaşık bir dakika içinde geçerli olur.
curl
curl -4 https://api.ipify.org
curl -6 https://api64.ipify.org

Bir istek engellendiğinde

Kayıtlı olmayan bir IP’den gelen istekler API’ye ulaşmadan durdurulur: JSON hata yerine HTTP 403 ile "Just a moment..." başlıklı bir HTML doğrulama (challenge) sayfası alırsınız. Hiç IP kaydetmediyseniz key’iniz IP ile sınırlı değildir, ancak sunucularınızdan gelen istekler bu sayfaya takılır. Bu sayfayı görüyorsanız sunucunuzun gerçekte hangi IP’yi kullandığını kontrol edip o adresi kaydedin.

En az bir IP kaydettiğiniz andan itibaren key’iniz yalnızca bu adreslerden kabul edilir. Key’inizle başka bir IP’den API’ye ulaşan istek 403 ve ip_not_allowed koduyla reddedilir; gövdede gördüğümüz IP de yer alır. Sızan bir key sunucularınızın dışında işe yaramaz.

403 yanıtı
{
  "message": "This API key is not allowed from your IP address. Register it under Allowed server IPs in your developer dashboard.",
  "code": "ip_not_allowed",
  "ip": "203.0.113.10"
}

Rate limit ve kotalar

Birbirinden bağımsız iki limit var; ikisi de partner başına sayılır, kimseyle paylaşılmaz.

Dakikada 240 istek

Ani yüklenme limiti. Her yanıt X-RateLimit-Limit ve X-RateLimit-Remaining header’larını taşır; hızınızı ona göre ayarlayabilirsiniz.

Günde 20000 istek

Onayda verilen varsayılan günlük kota. UTC gece yarısı sıfırlanır; talep üzerine yükseltiyoruz — beklediğiniz hacmi söyleyin, ona göre ayarlayalım.

İki limitten birini aşmak 429 döndürür. Endpoint kırılımıyla güncel kullanımınızı geliştirici panelinizden görebilirsiniz.

İçerik kuralları

Yeni turlar 30 gün bekletilir. Kataloğumuza eklenen bir tur, 30 günlük olana kadar partner arama sonuçlarında, tur detayında ve fiyat/müsaitlik yanıtlarında görünmez. Tek tur isteklerinde yanıt 404'tür; gövdede tour_embargoed kodu ve turun açılacağı tarih yer alır. Böylece tur önce kendi sitemizde indekslenir ve arama motorları asıl kaynağı doğru görür. Bundan eski her şey size tamamen açıktır. Aynı zamanda tedarikçimizseniz ve hesabınız tedarikçi şirketinize bağlıysa kendi turlarınız bu kuralın dışındadır: API üzerinden hemen, bekleme süresi olmadan erişilebilir.

Fiyat, tarih ve içerik her gün yeniden doğrulanır. İsterseniz yanıtları cache’leyin ama fiyat ve müsaitliği günde en az bir kez tazeleyin — ve rezervasyon oluşturmadan hemen önce müsaitliği mutlaka yeniden kontrol edin.

Katalog senkronizasyonu

Sayfalanmış iki değişiklik akışıyla herkese açık tur içeriğini ve güncel perakende hareket takvimlerini içe aktarın.

İlk taramada modified-since göndermeyin. Sonraki sayfalarda modified-since olmadan nextCursor değerini gönderin; nextCursor null olana kadar devam edin. İlk sayfanın syncStartedAt değerini kaydedip sonraki çalışmada modified-since olarak kullanın. Cursor tek bir partner hesabına ve tek bir akışa aittir. Kayıtları tourId ile güncelleyin; zaman sınırlarında aynı kayıt tekrar gelebilir.

İlk tarama yalnızca aktif, silinmemiş ve özel üretim olmayan turları içerir. Artımlı ürün akışı, önceden herkese açık bir tur durdurulduğunda, özel tura dönüştürüldüğünde veya mantıksal olarak silindiğinde kısa bir INACTIVE kaydı gönderir; bu turu ve kayıtlı takvimini kendi sisteminizde kaldırın veya gizleyin. Devre dışı turun içeriği ya da fiyatları gönderilmez. Takvim akışı yalnızca aktif turları içerir. İçerik ambargosu uygulanır; hesabınız bağlıysa kendi turlarınız muaftır. Sonraki kontrol noktası için kaydın modifiedAt değeri yerine syncStartedAt kullanın.

Hareket tarihleri veritabanında değişiklik olmadan geçmişte kalabilir. Geçmiş tarihleri kendi tarafınızda kaldırın; her artımlı takvim güncellemesi o turun kayıtlı takviminin tamamını değiştirir.

GET/b2b/api/products/modified-since

Yeni ve güncellenmiş turlar

ACTIVE kaydı tourId, slug, modifiedAt, status ve tam herkese açık tur içeriğiyle product alanını taşır. INACTIVE kaydı yalnızca tourId, slug, modifiedAt ve status içerir; kayıtlı turu kaldırın veya gizleyin. Yeniden yayınlanırsa ACTIVE olarak gelir. Net fiyatlar ve özel şirket alanları çıkarılır.

ParametreTipAçıklama
modified-sinceISO 8601Saat dilimi içeren zaman damgası; örneğin 2026-10-20T09:00:00Z. İlk tam tarama için göndermeyin.
countintegerSayfa boyutu 1–500; varsayılan 100.
cursorstringÖnceki sayfanın opak nextCursor değeri. modified-since olmadan gönderin.
İlk istek
curl -G '{BASE_URL}/b2b/api/products/modified-since' -H 'X-API-Key: YOUR_API_KEY' --data-urlencode 'count=100'
Sonraki sayfa
curl -G '{BASE_URL}/b2b/api/products/modified-since' -H 'X-API-Key: YOUR_API_KEY' --data-urlencode 'cursor=NEXT_CURSOR'
Yanıt (product kısaltılmıştır)
{
  "products": [
    {
      "tourId": 123,
      "slug": "example-tour",
      "modifiedAt": "2026-10-20T08:00:00+00:00",
      "status": "ACTIVE",
      "product": {
        "id": 123,
        "slug": "example-tour",
        "name": "Example tour",
        "itineraries": []
      }
    }
  ],
  "nextCursor": null,
  "syncStartedAt": "2026-10-20T09:00:00+00:00"
}
Artımlı kaldırma işareti
{
  "products": [
    {
      "tourId": 123,
      "slug": "example-tour",
      "modifiedAt": "2026-10-20T08:15:00+00:00",
      "status": "INACTIVE"
    }
  ],
  "nextCursor": null,
  "syncStartedAt": "2026-10-20T09:00:00+00:00"
}

INACTIVE kayıtları tur içeriği veya fiyat taşımaz. İlk taramada yalnızca aktif turlar bulunur. Sonraki mantıksal silmeler için tamamlanan artımlı tarama ve saklanan kontrol noktası, düzenli tam katalog karşılaştırmasının yerini alır. Aktif içerik geçici olarak erişilemezse 503 dönen sayfayı cursor değerini ilerletmeden yeniden isteyin.

GET/b2b/api/availability/schedules/modified-since

Güncellenmiş müsaitlik takvimleri

availabilitySchedules[] içindeki her kayıt tourId, slug, modifiedAt ve rates alanlarını içerir. rates yalnızca değişen kaydı değil, turun güncel perakende ücretlerinin tamamını taşır. Her ücretin dates alanında bugünden itibaren hareket tarihleri bulunur.

ParametreTipAçıklama
modified-sinceISO 8601Saat dilimi içeren zaman damgası. İlk tam tarama için göndermeyin.
countintegerSayfa boyutu 1–500; varsayılan 100.
cursorstringÖnceki sayfanın opak nextCursor değeri. modified-since olmadan gönderin.
Artımlı istek
curl -G '{BASE_URL}/b2b/api/availability/schedules/modified-since' -H 'X-API-Key: YOUR_API_KEY' --data-urlencode 'modified-since=2026-10-20T09:00:00Z'
Yanıt
{
  "availabilitySchedules": [
    {
      "tourId": 123,
      "slug": "example-tour",
      "modifiedAt": "2026-10-20T08:00:00+00:00",
      "rates": [
        {
          "rateId": 456,
          "startsAt": "2026-11-01",
          "endsAt": "2026-11-30",
          "minPax": 1,
          "maxPax": 20,
          "currency": "EUR",
          "departureTypeId": "scheduled",
          "description": {
            "en": "Standard departure"
          },
          "prices": {
            "regular": {
              "dbl": 200
            }
          },
          "dates": [
            "2026-11-05"
          ]
        }
      ]
    }
  ],
  "nextCursor": null,
  "syncStartedAt": "2026-10-20T09:00:00+00:00"
}

Son ücret kaydı silindiğinde tur rates: [] ile döner; böylece kayıtlı takvimini temizleyebilirsiniz. Bir ücretin geçerli dönemi olsa da dates: [] boş olabilir. Yalnızca perakende fiyatlar verilir; tedarikçi net fiyatları ve kâr marjı dönmez. Başarılı sayfalar Cache-Control: private, no-store kullanır.

Fiyat ve müsaitlik

Canlı hareket müsaitliği ve B2C perakende fiyatları. Partner API anahtarları tedarikçi net fiyatlarına erişim sağlamaz.

GET/b2b/api/apiv2/b2c/availability/{slug}

Bir turun müsaitliği ve fiyatı

Tek bir turun hareket müsaitliği ve perakende fiyatları.

ParametreTipAçıklama
roomTypestringsng, dbl veya trp. Varsayılan dbl.
dateYYYY-MM-DDTek bir hareket tarihi.
startDateYYYY-MM-DDTarih aralığının başlangıcı.
endDateYYYY-MM-DDTarih aralığının bitişi.
paxintegerYolcu sayısı.
service_typestringServis seviyesi. Varsayılan regular.
roomsarrayOda dağılımı: [{ id, pax, count }].
include_pricesyes | noFiyat kırılımını da döndürür.
include_roomsyes | noOda seçeneklerini de döndürür.

Müsait olmayan, silinen veya ambargodaki tur için 404 döner.

POST/b2b/api/apiv2/b2c/prices/{type}

Toplu fiyat

Bir id listesi için tur başına tek perakende fiyat — liste ve kategori sayfalarının ihtiyacı budur.

ParametreTipAçıklama
idszorunluinteger[]Fiyatlanacak tur id’leri.
roomTypestringsng, dbl veya trp. Varsayılan dbl.
startDateYYYY-MM-DDVarsayılan bugün.
endDateYYYY-MM-DDİsteğe bağlı aralık bitişi.

Müsait olmayan, silinen ve ambargodaki turlar yanıta dahil edilmez.

GET/b2b/api/apiv2/b2c/pricemonths/{type}/{id}

Müsait aylar

Bir turun müsait ay tarihleri; hareket takvimi oluşturmak için kullanılır. Bu uç fiyat döndürmez.

Müsait olmayan, silinen veya ambargodaki tur için 404 döner.

Destinasyonlar ve sınıflandırma

Filtrelerin, menülerin ve arama kutularının arkasındaki referans veri.

GET/b2b/api/apiv1/b2c/countries/list

Ülkeler

Tüm ülkeler; id, ad, slug ve telefon koduyla birlikte.

GET/b2b/api/apiv1/b2c/quicksearch/locations

Lokasyon arama

Destinasyonları ada göre arayın — şehir, bölge ve ülke.

ParametreTipAçıklama
qstringArama terimi.
idsstringVirgülle ayrılmış id’ler: arama yerine bilinen lokasyonları çözmek için.
limitintegerEn fazla sonuç, 1–50. Varsayılan 20.
GET/b2b/api/apiv1/location-parents/{id}

Lokasyonun üst zinciri

Bir lokasyonun üst zinciri (şehir → bölge → ülke); breadcrumb için.

GET/b2b/api/apiv1/b2c/quicksearch/tour-categories

Tur kategorileri

Terimle eşleşen kategori sayfaları; başlık ve URL’leriyle.

ParametreTipAçıklama
termstringArama terimi.
GET/b2b/api/apiv1/b2c/quicksearch/activities

Aktiviteler

Aktivite listesi (hiking, diving, …); id, ad ve slug ile — activities filtresinin kabul ettiği değerler.

ParametreTipAçıklama
termstringArama terimi.
GET/b2b/api/apiv1/b2c/tours/available-destinations

Turu olan destinasyonlar

Şu an rezerve edilebilir turu bulunan destinasyonlar.

Talepler ve rezervasyonlar

Kendi platformunuzdan bizim tarafta talep oluşturun. Burada oluşturduğunuz her kayıt partner hesabınıza atfedilir ve panelinizde görünür.

POST/b2b/api/apiv1/bookings/new-enquiry

Talep oluştur

Bir yolcunun tur hakkındaki sorusu. Talep kaydı oluşturur ve operatöre bildirim gider.

ParametreTipAçıklama
tour_idzorunluintegerSorulan tur.
contact_namezorunlustringYolcunun adı.
contact_emailzorunlustringYolcunun e-posta adresi.
messagezorunlustringSoru metni, en fazla 5000 karakter.
phone_codeintegerTelefon ülke kodunun location id’si.
contact_phonestringÜlke kodu olmadan telefon numarası.
buyer_currencyUSD | EURFiyatlamanın yapılacağı para birimi. Varsayılan EUR.

API key ile gelen isteklerde captcha aranmaz — kapı zaten key, kota ve rate limit’tir.

POST/b2b/api/apiv1/bookings/new-booking

Rezervasyon oluştur

Yolcular ve odalarla birlikte, B2C perakende müsaitlik fiyatıyla hesaplanan rezervasyon akışı. Ödemede kullanılan reference_id ve token değerlerini döner.

ParametreTipAçıklama
tour_idzorunluintegerRezerve edilen tur.
paxzorunluintegerYolcu sayısı.
datezorunluYYYY-MM-DDHareket tarihi; bugün veya sonrası.
service_typezorunlustringServis seviyesi; availability’nin döndürdüğü değer.
buyer_currencyzorunlustringYolcunun ödeme yapacağı para birimi. Satıcı para birimi turun kendi fiyat kaydından alınır.
roomsarrayKonaklamalı turlarda zorunlu: [{ id: "dbl", pax, count }].
customerszorunluarrayYolcular. İlki lider yolcudur; title, first_name, last_name, email, phone_code ve phone zorunludur.
GET/b2b/api/apiv1/bookings/{referenceId}

Rezervasyon detayı

Tek bir rezervasyonu okur. Rezervasyon token’ını ?token= ile gönderin — token erişimi yalnız o rezervasyonla sınırlar.

ParametreTipAçıklama
tokenzorunlustringRezervasyon oluşturulurken dönen token.
POST/b2b/api/apiv1/bookings/{referenceId}/payment-request

Tahsilat talebi aç

Kendi ön yüzünüzde barınan bir ödeme sayfası için rezervasyon üzerinden tahsilat başlatır. Tutar rezervasyondan hesaplanır — istemci belirleyemez.

ParametreTipAçıklama
tokenzorunlustringRezervasyon token’ı.
payment_modeltotal | depositKalan tutarın tamamı mı yoksa yalnız kapora mı tahsil edilecek.
GET/b2b/api/apiv1/bookings/{referenceId}/payment-request/{id}

Tahsilat talebinin durumu

Bir tahsilat talebinin durumunu sorgular. Aynı token gerekir.

ParametreTipAçıklama
tokenzorunlustringRezervasyon token’ı.
POST/b2b/api/apiv1/bookings/abandoned-cart

Terk edilen sepeti bildir

Bir yolcunun rezervasyona başlayıp tamamlamadığını bildirir; ekibimiz takip eder. Rezervasyon kaydı oluşturmaz.

ParametreTipAçıklama
sourcezorunlutsb | tstSepetin hangi vitrinden geldiği.
tourzorunlustringTur slug’ı.
namestringYolcunun adı.
emailstringYolcunun e-posta adresi.
phone_codeintegerTelefon ülke kodunun location id’si.
phonestringTelefon numarası.
dateYYYY-MM-DDPlanlanan hareket tarihi.
paxintegerYolcu sayısı.

Kullanımdan kaldırılan yanıt alanları

3 Kasım 2026’dan itibaren tur arama, tur detayı ve ürün akışı aşağıdaki alanları null olarak döndürür. Mevcut entegrasyonlar bozulmasın diye anahtarlar 1 Mayıs 2027’ye kadar yanıtta kalır; bu tarihten sonra kaldırılır. Bu alanlara dayanan geliştirme yapmayın.

Tur alanları: guides, transfers, additional_service_location, is_bokun_completed, free_cancelation, all_inclusive, type, vat, deleted_at, b2c, bokun_id, sales, meta_title, meta_description, content_score ve defaults.content_score.

Yorumlar: reviews null döner. rating ve review_count özeti dönmeye devam eder.

name_en 1 Mayıs 2027’ye kadar değeriyle dönmeye devam eder, sonra kaldırılır. Yerine name alanını kullanın.

Fiyat alanları: trp_, chd_ ve inf_ en düşük fiyatları (min_reg_price, min_prv_price ve _pax varyantları), sng_/dbl_/unit_/adl_min_reg_price_pax ve min_prv_price_pax. price ile sng_/dbl_/unit_/adl_ min_reg_price, min_prv_price ve min_prv_price_pax alanlarını kullanmaya devam edin; kesin fiyat ve müsaitlik için fiyat endpoint’lerini çağırın.

rates[].dates[] içinde id, rate_id ve tour_id null döner; date değişmedi.

Hatalar

Hatalar standart HTTP durum kodlarını kullanır; gövdede bir message ve — doğrulama hatalarında — alan adlarıyla anahtarlanmış bir errors nesnesi döner.

KodAnlamıNe yapmalı
200OKİstek başarılı.
401UnauthorizedX-API-Key header’ı yok ya da key tanınmıyor. Ürettiğiniz key’i gönderdiğinizden emin olun — yerine geçtiği eskisini değil.
403ForbiddenAPI erişiminiz askıya alınmış ya da henüz onaylanmamış. Bir hata olduğunu düşünüyorsanız bize yazın.
403IP izinli değilGövdede ip_not_allowed kodu ve gördüğümüz ip yer alır. Key’iniz kaydettiğiniz sunucu IP’lerine bağlıdır ve bu istek başka bir adresten geldi. O adresi geliştirici panelinizden kaydedin ya da isteği kayıtlı bir sunucudan gönderin.
403Doğrulama sayfasıJSON yerine "Just a moment..." başlıklı bir HTML sayfası. İstek izin listenizde olmayan bir IP’den geldi ve API’ye ulaşmadan durduruldu. Sunucunuzun giden IP adresini geliştirici panelinizden kaydedin; değişiklikler yaklaşık bir dakika içinde geçerli olur.
404Not foundTur, rezervasyon veya lokasyon kullanılamaz, silinmiş, ambargoda ya da bilinmiyor olabilir; token ile sınırlı uçlarda token eşleşmiyor olabilir.
422UnprocessableDoğrulama başarısız. Gövdede message bulunur; alan doğrulaması errors nesnesi de içerebilir. Değişiklik akışlarında zaman damgasını, count ve cursor değerlerini kontrol edin; cursor ile modified-since birlikte gönderilmez.
429Too many requestsDakikalık rate limit’i ya da günlük kotanızı aştınız. X-RateLimit-Remaining header’ına bakıp hızınızı düşürün.
503Geçici olarak erişilemiyorÜrün değişiklik akışı turun tüm içeriğini okuyamadı. Retry-After süresini bekleyip cursor değerini kaydetmeden veya ilerletmeden aynı sayfayı yeniden isteyin.
500Server errorBizim tarafta bir şey hata verdi. Artan aralıklarla tekrar deneyin; sürerse isteğin saatiyle birlikte bize ulaşın.
422 yanıtı
{
  "message": "The given data was invalid.",
  "errors": {
    "tour_id": ["The selected tour id is invalid."],
    "customers.0.email": ["The customers.0.email must be a valid email address."]
  }
}

Sürümleme

Bazı endpoint’ler tarihsel /b2b/api/apiv1/… veya /b2b/api/apiv2/… yolunu korur. Katalog değişiklik akışları dâhil native partner endpoint’leri doğrudan /b2b/api/… altında bulunur. Hepsi canlı ve bakımdadır.

Bir sürüm içinde yalnızca ekleme yaparız — yeni alan, yeni endpoint. Halihazırda kullandığınız alanları yeniden adlandırmaz ya da kaldırmayız. Entegrasyonu bozacak her şey yeni bir sürüm yolunda yayına girer ve bir sürüm emekliye ayrılmadan önce tüm aktif partnerlara e-posta göndeririz.

Geliştirmeye hazır mısınız?

Erişim için başvurun ve key’inizi üretin. Hangi entegrasyonun size uyduğunu mu merak ediyorsunuz? Ekibimiz yardımcı olmaktan memnun olur.