Tranigo · API

API Kullanım Kılavuzu

Tranigo ağındaki havalimanı ve şehir içi transferleri kendi sisteminizden aramak, satmak ve takip etmek için.

Adreshttps://api.citytransferturkey.com
BiçimJSON (UTF-8), alan adları camelCase, enum'lar metin ("OnAccount").
Tarih / saatTarih YYYY-MM-DD; alış saati Türkiye yerel saati HH:mm; zaman damgaları ISO-8601 (UTC).
SürümPartner API: /v1 · Mobil müşteri API'si: /mobile/v1

Bu sayfa akışı ve kuralları anlatır. Her alanın tam tanımı için Swagger sayfasına bakın; oradan istekleri doğrudan deneyebilirsiniz.

Kimlik doğrulama

Sunucudan sunucuya entegrasyonda API anahtarı kullanılır. Anahtarı acenta panelinde API & Webhook sayfasından üretirsiniz; anahtar yalnızca bir kez gösterilir, bizde saklanmaz.

AnahtarModNe olur
ctt_live_…CanlıGerçek rezervasyon açılır, sağlayıcıya iletilir, cari hesabınıza yazılır.
ctt_test_…SandboxHiçbir şey gerçek değildir: transfer oluşmaz, cariye yazılmaz, ödeme taklit edilir.

Anahtarı iki şekilde gönderebilirsiniz:

Authorization: Bearer ctt_live_xxxxxxxxxxxxxxxx
# ya da
X-Api-Key: ctt_live_xxxxxxxxxxxxxxxx
Anahtarı tarayıcıda, mobil uygulamada ya da herkese açık kodda kullanmayın; yalnızca sunucunuzda saklayın. Sızdığından şüphelenirseniz panelden hemen iptal edip yenisini üretin. Mobil uygulama ya da kendi panel arayüzünüz için acenta kullanıcı girişini kullanın.

Bağlantıyı denemek için:

curl https://api.citytransferturkey.com/v1/me \
  -H "Authorization: Bearer ctt_test_xxxxxxxx"

Yanıtta firma bilginiz, modunuz (live/test), komisyon oranınız ve cari hesabınızın açık olup olmadığı döner.

Hızlı başlangıç

Bir rezervasyon dört çağrıdır. Önce ctt_test_ anahtarıyla deneyin.

  1. Konum bulun — havalimanı ya da otel bölgesinin kimliği:
    curl "https://api.citytransferturkey.com/v1/locations?q=antalya" \
      -H "Authorization: Bearer $CTT_KEY"
  2. Teklif alın — güzergah, tarih ve yolcu sayısına göre araçlar ve fiyatlar (30 dakika geçerli):
    curl -X POST https://api.citytransferturkey.com/v1/quotes \
      -H "Authorization: Bearer $CTT_KEY" -H "Content-Type: application/json" \
      -d '{"fromRegionId":"…","toRegionId":"…","date":"2026-11-20","passengers":2}'
  3. Rezervasyon açın — seçtiğiniz teklif, yolcu bilgisi ve kendi rezervasyon numaranızla:
    curl -X POST https://api.citytransferturkey.com/v1/bookings \
      -H "Authorization: Bearer $CTT_KEY" -H "Content-Type: application/json" \
      -d '{
        "quoteId": "…",
        "paymentMethod": "OnAccount",
        "externalReference": "ACN-2026-0042",
        "pickupDate": "2026-11-20",
        "pickupTime": "14:30",
        "passenger": { "firstName": "Ayşe", "lastName": "Yılmaz", "phoneCode": "+90",
                       "phone": "5551112233", "email": "ayse@example.com" },
        "passengerCount": 2,
        "flightCode": "TK2412",
        "hotelAddress": "Lara Cd. No:1, Antalya"
      }'
  4. Takip edin — GET /v1/bookings/{code} ile ya da webhook'larla durum değişikliklerini alın.

Konumlar ve teklif

GET /v1/locations?q=… en az 2 karakterle havalimanı/bölge arar. GET /v1/locations/{regionId}/destinations o bölgeden fiyatı olan varış noktalarını verir.

POST /v1/quotes uygun araçları döner. Her teklifte:

AlanAçıklama
quoteIdRezervasyonda kullanılır. 30 dakika geçerli, tek kullanımlık, size ve bu güzergah/tarihe bağlı.
price, currencyYolcuya satış fiyatı (yön başına).
commission, netPriceKomisyonunuz ve net tutar (satış − komisyon). Net fiyat modundaki partnerler için netPrice bize ödenecek tutardır.
passengerCapacity, luggageCapacityAraç kapasitesi. Yolcu sayısı kapasiteyi aşamaz.

Sağlayıcının kapalı günü olan ya da en az rezervasyon süresine (ör. 12 saat önceden) yetişmeyen araçlar teklifte hiç görünmez. İsteğe "currency": "EUR" ekleyerek fiyat dövizini seçebilirsiniz (TRY, EUR, USD); verilmezse hesabınızın dövizi kullanılır.

Rezervasyon açma

POST /v1/bookings — yeni rezervasyon 201, aynı externalReference ile daha önce açılmış rezervasyon 200 döner.

Tekrar deneme güvenliği (idempotency)

externalReference sizin rezervasyon numaranızdır ve hesabınızda benzersizdir. Ağ hatasında isteği aynı numarayla tekrar göndermeniz yeterli: ikinci kez rezervasyon açılmaz, mevcut olan döner. Bu alanı her zaman göndermenizi öneririz.

Dönüş transferi

İsteğe "return": {"date":"2026-11-25","time":"10:00","flightCode":"TK2413","hotelAddress":"…"} ekleyin. Dönüş ayrı bir rezervasyon kodu (…-R) alır; yanıtta return alanında gelir. Gidişi iptal etmek dönüşü de iptal eder.

Yanıt

{
  "booking": { "code": "CTT7K2M9Q", "externalReference": "ACN-2026-0042", "status": "Pending",
               "scheduledDate": "2026-11-20", "scheduledTime": "14:30", "price": 120.00, "currency": "EUR",
               "commission": 12.00, "commissionCurrency": "EUR", "isTest": false, … },
  "return": null,
  "payment": { "method": "OnAccount", "status": "Paid", "online": null }
}

Ödeme seçenekleri

paymentMethodKim öderNasıl işler
OnAccountSiz (cari)Net tutar cari hesabınıza borç yazılır. Kredi limiti tanımlı olmalı; limit ya da vadesi geçmiş borç aşılırsa 422.
OnAccount + "partnerPaysByCard": trueSiz (kart)Net tutarı kendi kartınızla ödersiniz; kredi limiti gerekmez. Yanıttaki payment.online.url sayfasında ödeyin. Ödeme gelince cariye borç ve tahsilat birlikte yazılır.
CreditCardYolcu (kart)Yanıttaki payment.online.url linkini yolcunuza iletin; yolcu satış fiyatını kartla öder. Komisyonunuz transfer tamamlanınca carinize alacak yazılır. Net fiyat modunda yoktur.
CashYolcu (nakit)Sürücü yolcudan tahsil eder; komisyonunuz transfer tamamlanınca carinize yazılır. Net fiyat modunda yoktur.

Kartla ödeme beklenen rezervasyon

"payment": {
  "method": null, "status": null,
  "online": {
    "url": "https://citytransferturkey.com/en/Pay/Ab3dEf7hJk9m",
    "paidBy": "passenger",            // "passenger" | "partner"
    "amount": 120.00, "currency": "EUR",
    "dueAt": "2026-11-12T09:14:00Z",
    "status": "awaiting_payment",     // awaiting_payment | paid | cancelled | expired
    "paidAt": null
  }
}
Ödeme süresi en fazla 24 saattir ve ilk alıştan en az 1 saat önce dolar. Süre içinde ödenmeyen rezervasyon otomatik iptal edilir (booking.cancelled webhook'u gider). Transfere 75 dakikadan az kaldıysa kartlı seçenekler kabul edilmez (422). Ödeme gelince booking.paid webhook'u gider.

Sitenizde kartla ödeme

CreditCard (yolcu öder) rezervasyonda yolcuyu bizim ödeme sayfamıza göndermek yerine kart formunu kendi sitenizde gösterebilirsiniz. Kart bilgisi sunucunuzdan bize iletilir; sitenizden çıkılan tek adım bankanın 3D Secure sayfasıdır, ardından müşteri sizin sayfanıza döner.

Önce: dönüş sayfanızın alan adlarını (ör. www.siteniz.com) bize bildirin; hesabınıza tanımlanmadan bu uç nokta 422 errors/return_hosts_not_configured döner. Yalnızca https ve tam eşleşme (alt alan adları ayrıca yazılır).
curl -X POST https://api.citytransferturkey.com/v1/bookings/CTT7K2M9Q/payments/card \
  -H "Authorization: Bearer ctt_live_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{ "cardHolderName": "Ali Veli", "cardNumber": "5528790000000008",
        "expireMonth": "12", "expireYear": "2030", "cvc": "123",
        "returnUrl": "https://www.siteniz.com/en/booking/confirmation/ABC123",
        "customerIp": "203.0.113.7" }'
AlanAçıklama
cardHolderName, cardNumber, cvcKart bilgisi (numaradaki boşluk / tire yok sayılır).
expireMonth, expireYear"12" / "2030" (yıl "30" da olur).
returnUrl3D Secure sonrası müşterinin döneceği sayfanız (mutlak https, izinli alan adı, # parçası yok).
customerIpSon müşterinin IP adresi (önerilir; boşsa sunucunuzun IP'si kullanılır).

Yanıt (200)

{ "status": "redirect",   // redirect | paid | failed
  "html": "<form …>…",    // yalnızca redirect: bankanın 3D Secure sayfası
  "message": null, "errorCode": null }
  • redirect: html'i müşterinin tarayıcısına olduğu gibi (text/html) gönderin. Banka doğrulamasından sonra tarayıcı returnUrl'e döner; sorgu dizesine payment=success, payment=failed ya da payment=pending eklenir. Bu parametre yalnızca bilgi içindir — sonucu her zaman GET /v1/bookings/{code} ile doğrulayın (payment.online.status = "paid"). Ödeme gelince booking.paid webhook'u da gider.
  • paid: ödeme alındı (sandbox'ta her zaman bu döner).
  • failed: message'ı müşteriye gösterin. errorCode: invalid_card_holder, invalid_card_number, invalid_card_expiry, invalid_card_cvc, card_declined, three_ds_failed, payment_pending, payment_unknown (sonuç doğrulanamadı — tekrar denetmeyin, rezervasyon durumunu kontrol edin), payment_unavailable, too_many_attempts (bir rezervasyonda son bir saatte 5 başarısız ya da 10 deneme).
HataNe zaman
400Eksik alan, geçersiz returnUrl ya da customerIp
404Rezervasyon yok, size ait değil ya da diğer moddan (canlı / test)
409errors/not_payable: bekleyen yolcu kart ödemesi yok (nakit, cari, kendi kartınızla ödediğiniz rezervasyon), iptal ya da ödeme süresi dolmuş · errors/already_paid
422errors/return_hosts_not_configured · errors/return_host_not_allowed (alan adı listede değil ya da https değil)
Güvenlik: kart bilgisini sitenizde ve sunucunuzda saklamayın, loglamayın; yalnızca bu isteğe iletin. Biz de saklamıyoruz. İstek 503 alırsa otomatik tekrar denemeyin (ödeme başlamış olabilir) — önce rezervasyon durumuna bakın.

Sitenizde PayPal ile ödeme

Aynı CreditCard (yolcu öder) rezervasyonda PayPal butonlarını (PayPal JS SDK, Smart Buttons) kendi sayfanızda gösterebilirsiniz. Siteden çıkılan tek şey PayPal'ın kendi penceresidir; order açma ve parayı çekme (capture) sunucunuzdan bize gelir. Dönüş alan adı gerekmez. Ödeme koşulları, deneme sınırı ve hatalar kartla ödeme ile aynıdır.

1. SDK bilgisi

curl https://api.citytransferturkey.com/v1/bookings/CTT7K2M9Q/payments/paypal \
  -H "Authorization: Bearer ctt_live_xxxxxxxx"

{ "simulated": false, "clientId": "AXk…", "amount": 120.00, "currency": "EUR", "intent": "capture" }

Sayfanıza https://www.paypal.com/sdk/js?client-id={clientId}&currency={currency}&intent=capture yükleyin. amount / currency PayPal'da çekilecek tutardır (TRY rezervasyonda EUR'ya çevrilmiş olabilir). PayPal kapalıysa ya da bu para biriminde kullanılamıyorsa 422 errors/paypal_not_available döner — PayPal butonunu göstermeyin.

2. Order (butonun createOrder'ı)

curl -X POST https://api.citytransferturkey.com/v1/bookings/CTT7K2M9Q/payments/paypal/order \
  -H "Authorization: Bearer ctt_live_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{ "customerIp": "203.0.113.7" }'

{ "orderId": "5O190127TN364715T" }

Tutar ve ödeyici (yolcu) rezervasyondan alınır; gövde isteğe bağlıdır. Müşteri PayPal penceresini kapatıp yeniden açarsa aynı açık order döner. orderId'yi createOrder'dan döndürün.

3. Capture (butonun onApprove'u)

curl -X POST https://api.citytransferturkey.com/v1/bookings/CTT7K2M9Q/payments/paypal/capture \
  -H "Authorization: Bearer ctt_live_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{ "orderId": "5O190127TN364715T" }'

{ "status": "paid", "message": null, "errorCode": null }   // paid | pending | failed
  • paid: ödeme alındı; booking.paid webhook'u gider. Aynı orderId tekrar gönderilirse PayPal'a gidilmeden yine son durum döner (idempotent).
  • pending: payment_pending (PayPal incelemesinde) ya da payment_unknown (sonuç doğrulanamadı) — müşteriye tekrar ödetmeyin, durumu GET /v1/bookings/{code} ile izleyin.
  • failed: payment_retry → PayPal ödeme kaynağını reddetti; SDK'da actions.restart() çağırın, müşteri başka kaynak seçsin. payment_declined → message'ı gösterin.
HataNe zaman
400Eksik orderId ya da geçersiz customerIp
404Rezervasyon yok, size ait değil ya da diğer moddan (canlı / test)
409errors/not_payable · errors/already_paid (kartla aynı; iptal edilen rezervasyonda açık order capture edilmez)
422errors/paypal_not_available · errors/too_many_attempts (kartla ortak sınır) · errors/payment_unavailable (order açılamadı, sonra tekrar deneyin) · errors/unknown_order (order bu rezervasyonun değil)
Capture isteği 503 alırsa otomatik tekrar denemeyin — önce rezervasyon durumuna bakın (capture idempotent olsa da sonucu doğrulamak yeterli).

Durumlar ve iptal

DurumAnlamı
PendingAlındı, sağlayıcı onayı bekleniyor.
ConfirmedSağlayıcı onayladı.
CompletedTransfer yapıldı.
Cancelledİptal (cancellationReason alanında neden).

POST /v1/bookings/{code}/cancel gövde: {"reason":"Müşteri vazgeçti"} (isteğe bağlı). Sözleşmenizdeki ücretsiz iptal süresi geçtiyse (ör. alıştan 24 saat öncesine kadar) geç iptal ücreti cari hesabınıza yazılır; cari rezervasyonun borcu ters kaydedilir. Tamamlanmış ya da zaten iptal edilmiş rezervasyon iptal edilemez (422).

GET /v1/bookings listeleme: status, dateFrom, dateTo, search, page, pageSize (en fazla 100).

Sandbox (test)

ctt_test_ anahtarıyla her şeyi gerçek veri üretmeden deneyin. Test rezervasyonları canlı kayıtlarınızla karışmaz (ayrı listelenir), sağlayıcıya gitmez, cariye yazılmaz. Webhook'lar "livemode": false ile gönderilir.

Kartlı test rezervasyonunda gerçek ödeme linki oluşmaz (payment.online.url = null). Ödemeyi taklit etmek için:

curl -X POST https://api.citytransferturkey.com/v1/bookings/CTT7K2M9Q/simulate-payment \
  -H "Authorization: Bearer ctt_test_xxxxxxxx"

Bu uç nokta canlı anahtarla 403 döner.

Sitenizde kartla ödeme (POST /v1/bookings/{code}/payments/card) sandbox'ta da çalışır: kart alanları canlıdaki gibi doğrulanır (Luhn, son kullanma, CVC) ve dönüş alan adı kontrol edilir, ama bankaya gidilmez — ödeme simulate-payment ile aynı yoldan işlenir ve yanıt doğrudan "paid" olur (3D Secure adımı yoktur). Test için Luhn'u geçen herhangi bir numara (ör. 4111111111111111) kullanılabilir.

Sitenizde PayPal ile ödeme sandbox'ta PayPal'a gitmez: GET …/payments/paypal "simulated": true ve clientId: null döner (SDK yüklemeyin; PayPal ayarından bağımsız, tutar rezervasyonun tutarıdır). …/paypal/order TEST- ile başlayan bir orderId döner; bunu …/paypal/capture'a gönderince ödeme simulate-payment ile aynı yoldan işlenir ve "paid" döner. Sayfanızda SDK yerine "Test: PayPal ile öde (taklit)" gibi bir buton gösterip bu iki çağrıyı yapabilirsiniz.

Webhook'lar

Panelde API & Webhook sayfasından bir HTTPS adresi girin; rezervasyonlarınızdaki her değişiklik bu adrese imzalı POST olarak gelir. İmza sırrı (whsec_…) yalnızca oluşturulduğunda bir kez gösterilir.

OlayNe zaman
booking.createdRezervasyon açıldı
booking.paidKartla ödemesi beklenen rezervasyonun ödemesi alındı
booking.confirmedSağlayıcı onayladı
booking.completedTransfer tamamlandı
booking.cancelledİptal edildi (siz, biz ya da ödeme süresi dolduğu için)

İstek

POST /ctt-webhook HTTP/1.1
Content-Type: application/json
User-Agent: CityTransferTurkey-Webhooks/1.0
X-CTT-Event: booking.confirmed
X-CTT-Delivery: 6f1c…            (her gönderimin kimliği — tekrarları ayıklamak için)
X-CTT-Signature: t=1763630000,v1=5a0d…

{ "id": "…", "event": "booking.confirmed", "createdAt": "2026-11-12T08:00:00Z",
  "livemode": true, "data": { "code": "CTT7K2M9Q", "status": "Confirmed", … } }

İmzayı doğrulama

v1 = hex( HMAC-SHA256( sır, t + "." + ham_gövde ) ). Gövdeyi JSON olarak çözmeden önce, ham haliyle doğrulayın ve t'nin son 5 dakika içinde olduğunu kontrol edin (tekrar saldırısına karşı).

const crypto = require("crypto");

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Teslim ve tekrar

Adresiniz 10 saniye içinde 2xx dönmelidir; dönmezse 1 dk, 5 dk, 15 dk, 30 dk, 1 sa, 3 sa, 6 sa, 12 sa aralıklarla 8 kez tekrar denenir. Yönlendirmeler (3xx) izlenmez. Aynı olay birden fazla gelebilir — X-CTT-Delivery ya da gövdedeki id ile ayıklayın; olaylar sırasız gelebilir, karar verirken data.status'a bakın. Başarısız gönderimleri panelden tekrar kuyruğa alabilirsiniz.

Cari hesap

GET /v1/account — bakiye (pozitif: bize borcunuz, negatif: alacağınız), kredi limiti, kullanılabilir tutar, vadesi geçmiş borç.

GET /v1/account/statement?from=…&to=…&page=1&pageSize=100 — hareket dökümü: rezervasyon borcu, komisyon alacağı, ödeme, geç iptal ücreti, ters kayıtlar ve yürüyen bakiye. Aylık ekstre ayrıca e-postanıza gönderilir.

Hatalar

Hatalar RFC 9457 application/problem+json biçimindedir; detail alanı insan için açıklamadır.

{ "type": "https://api.citytransferturkey.com/errors/business_rule",
  "title": "Business rule violation", "status": 422,
  "detail": "Kredi limiti aşılıyor. Kullanılabilir: 40,00 EUR, gereken: 108,00 EUR.",
  "traceId": "00-…" }
KodNe zamanNe yapmalı
400Eksik / hatalı alan (errors alanında ayrıntı)İsteği düzeltin.
401Anahtar/token yok, hatalı, iptal edilmiş ya da süresi dolmuşAnahtarı kontrol edin; token'ı yenileyin.
403Bu kimlikle bu işlem yapılamaz (ör. canlı anahtarla simulate-payment)Doğru anahtar/token'ı kullanın.
404Rezervasyon yok ya da size ait değilKodu kontrol edin.
409Kart / PayPal ödemesi yapılamaz: errors/not_payable (bekleyen yolcu kart ödemesi yok, iptal ya da süresi dolmuş) / errors/already_paidRezervasyonun güncel durumunu alın.
422İş kuralı: kredi limiti, süresi dolmuş teklif, kapalı gün, kapasite, iptal edilemez durum…detail'ı kullanıcıya gösterin; teklif süresi dolduysa yeniden teklif alın.
429Hız sınırıRetry-After saniye kadar bekleyin.
5xxBizim tarafta geçici sorunAynı externalReference ile güvenle tekrar deneyin.

Hız sınırları

KimlikSınır
API anahtarı / acenta token'ıPartner başına dakikada 120 istek
Mobil müşteri token'ıMüşteri başına dakikada 120 istek
Kimliksiz istekler (arama vb.)IP başına dakikada 30 istek
Giriş / kayıt / yenileme / şifre sıfırlamaIP başına dakikada 10 istek

Sınır aşılınca 429 ve Retry-After başlığı döner. Teklif sonuçlarını kısa süre (≤30 dk) önbelleğe alarak istek sayınızı azaltabilirsiniz.

Acenta kullanıcı girişi

Kendi mobil uygulamanız ya da panel arayüzünüz için API anahtarı yerine acenta panelindeki kullanıcı e-posta/şifresiyle token alın. Token'la bütün /v1 uç noktaları aynı çalışır (yalnızca canlı mod).

POST /v1/auth/login     { "email": "ops@acenta.com", "password": "…", "deviceName": "iPhone" }
→ 200 { "accessToken": "cttm_…", "tokenType": "Bearer", "expiresAt": "…",
        "refreshToken": "cttr_…", "refreshTokenExpiresAt": "…" }

GET  /v1/bookings       Authorization: Bearer cttm_…
POST /v1/auth/refresh   { "refreshToken": "cttr_…" }   → yeni token çifti
POST /v1/auth/logout    { "refreshToken": "cttr_…" }   → 204
Erişim token'ı 60 dakika, yenileme token'ı 60 gün geçerlidir. Yenileme token'ı her kullanımda değişir — dönen yenisini saklayın, eskisini atın. Aynı yenileme token'ı ikinci kez gönderilirse güvenlik için oturum kapatılır. Kullanıcı panelden silinir ya da partner pasif edilirse token anında geçersizleşir.
İki adımlı doğrulama: Hesabında iki adımlı doğrulama (2FA) açık olan kullanıcıda giriş iki adımlıdır. Şifre doğruysa token yerine 403 döner; yanıtta "twoFactorRequired": true ve challenge (5 dakika geçerli) vardır. Doğrulama uygulamasındaki kodla devam edin:
POST /v1/auth/2fa       { "challenge": "…", "code": "123456", "deviceName": "iPhone" }   → 200 token çifti
Yanlış kod 401; aynı kullanıcıda 5 hatalı kod 15 dakika kilitler. Kullanıcı 2FA'yı sonradan açarsa önceki uygulama / API oturumları kapanır, yeniden giriş gerekir. API anahtarıyla bağlantı bundan etkilenmez.

Mobil müşteri API'si

Tranigo mobil uygulaması içindir; web sitesindeki müşteri hesabıyla aynı hesap kullanılır. Tam referans: Swagger · Mobile API.

Uç noktaAçıklama
POST/mobile/v1/auth/registerHesap aç → token çifti (e-posta kayıtlıysa 409)
POST/mobile/v1/auth/loginGiriş → token çifti
POST/mobile/v1/auth/refresh · /logoutToken yenile / çıkış
POST/mobile/v1/auth/forgot-password · /reset-password6 haneli e-posta koduyla şifre sıfırlama
GET PUT/POST/mobile/v1/meProfil (güncellemede POST önerilir: bazı sunucu güvenlik duvarları PUT isteğini keser); POST /mobile/v1/me/password şifre değiştir
GET/mobile/v1/locations?q=Konum arama (giriş gerekmez)
GET/mobile/v1/search?fromRegionId&toRegionId&date&passengers&currencyFiyatlı araçlar, priceId ve kabul edilen ödeme yöntemleri (giriş gerekmez)
POST/mobile/v1/bookingsRezervasyon; yanıttaki payment.url ödeme sayfasıdır. İsteğe bağlı couponCode (geçersizse 422) ve useWallet: true (sadakat cüzdanı bakiyesi indirim olarak kullanılır)
GET/mobile/v1/bookings · /{code}Rezervasyonlarım
GET/mobile/v1/tours/suggest?q&languageTur araması (en az 3 harf): turu olan şehirler, kategoriler, turlar (giriş gerekmez)
GET/mobile/v1/tours?cityId&areaId&date&currency&language&sort&page&pageSizeŞehrin turları; filtreler priceMin, priceMax, durations, themes, guideLanguages (çok değerde parametre tekrarlanır) (giriş gerekmez)
GET/mobile/v1/tours/{tourId}?date&currency&languageTur detayı ve rezervasyon seçenekleri: kalkış saatleri, rehber dilleri, alış noktaları (giriş gerekmez)
GET/mobile/v1/tours/{tourId}/quote?date&adults&childAges&currencyKesin fiyat, kalem kalem; status Ok değilse rezervasyon açılamaz (giriş gerekmez)
POST/mobile/v1/tour-bookingsTur rezervasyonu; yanıttaki payment.url tur ödeme sayfasıdır. Kural ihlalinde 422, nedeni reason alanında
GET/mobile/v1/tour-bookings · /{code}Tur rezervasyonlarım
POST/mobile/v1/auth/appleApple ile giriş (iOS): identityToken, authorizationCode, nonce, ilk girişte ad/soyad → token çifti. Hesap Apple kimliği ya da Apple'ın doğruladığı e-postayla eşleşir, yoksa açılır. 401 geçersiz token, 422 e-posta yok, 503 kapalı
POST/mobile/v1/me/deleteHesabı sil: { "password": "…" } (şifresiz Apple/Google hesabında boş). Kişisel bilgiler silinir, oturumlar kapanır, Apple token'ı iptal edilir; rezervasyon kayıtları kalır. 422 reason: WrongPassword, ActiveReservations
GET/mobile/v1/app/config?platform&versionAçılış ayarları: updateRequired (bu sürüm artık kullanılamaz), updateAvailable, mağaza linki, destek telefonu / e-posta / WhatsApp (giriş gerekmez)
POST/mobile/v1/app/installationsKurulum bilgisi: installationId, platform, sürüm, dil, push token ve izin. Her açılışta, girişten sonra ve token değişince; müşteri token'ı varsa kurulum müşteriye bağlanır (giriş gerekmez)
POST/mobile/v1/app/installations/{installationId}/sign-outÇıkıştan önce: kurulumun müşteri bağı kaldırılır
POST/mobile/v1/app/campaigns/{campaignId}/openedKampanya bildirimine dokunuldu: { "installationId": "…" }. Admin ekranındaki "Açılma" sayısı; aynı kurulumun tekrarı sayılmaz (giriş gerekmez)
GET/mobile/v1/app/inboxBildirim geçmişi (zil): giriş yapıldıysa hesaba giden bildirimler + bu kuruluma (X-Installation-Id) giden kampanyalar; unreadCount ve en yeni 100 satır (kind, başlık, metin, url, read). 90 gün tutulur (giriş gerekmez)
POST/mobile/v1/app/inbox/readZil ekranı açıldı: görünen bildirimlerin hepsi okundu (giriş gerekmez)
GET/mobile/v1/home?language&currencyAna sayfa: turu olan şehirler (tur sayısına göre) ve öne çıkan turlar, bugünün başlangıç fiyatıyla; 10 dk önbellek (giriş gerekmez)
POST/mobile/v1/auth/googleGoogle ile giriş: { "idToken": "…", "deviceName": "…" } → token çifti. Token Admin → Ayarlar → Google ile Giriş'teki web ya da mobil Client ID'lerinden birine verilmiş olmalı. 401 geçersiz token, 422 e-posta doğrulanmamış, 503 kapalı
POST/mobile/v1/me/email/verify · /email/resendE-posta doğrulama: 6 haneli kod → güncel profil (isEmailVerified, pendingEmail). 422 reason: InvalidCode, Expired, TooManyAttempts. Doğrulanınca aynı e-postayla yapılmış misafir rezervasyonlar hesaba bağlanır
GET/mobile/v1/links/reservation/{token} · /links/review/{token}E-postadaki /{dil}/my-booking/{token} ve /{dil}/review/{token} bağlantılarının rezervasyonu: { kind, code }; geçersizse 404 (giriş gerekmez)
GET/mobile/v1/bookings/{code}/manageTransfer: iptal / değişiklik yapılabilir mi, son an (cancelDeadline), iptal ücreti (%), tahmini kart iadesi, cüzdana dönecek tutar, değiştirilebilir bilgiler
POST/mobile/v1/bookings/{code}/cancelTransfer iptali (gidiş-dönüşte kalan bacaklarla); kartla ödenmişse ücret düşülerek iade. refundPending: true = otomatik iade yapılamadı, ekip elle iade eder. 422 reason: Disabled, TooLate, NotCancellable, PartnerBooking
PUT/POST/mobile/v1/bookings/{code}/details(POST önerilir) Yolcu, yolcu sayısı, tarih-saat (HH:mm), uçuş / otel değişikliği (iptal süresiyle aynı pencere; değişen alanlar admine bildirilir). 422 reason: TooLate, Invalid
GET/mobile/v1/vouchers/{transfer|tour}/{code}?languageVoucher PDF adresi ve dosya adı (QR'lı; uygulama indirip saklar, çevrimdışı da açılır)
GET POST/mobile/v1/messages/{transfer|tour}/{code}Rezervasyon yazışması (açınca ekibin mesajları okundu sayılır) / mesaj gönder { "text": "…" }. 422 reason: Empty, TooLong, TooManyLinks, RateLimited. Ekip cevap yazınca e-posta + bildirim (data.url = /messages/{kind}/{code})
GET/mobile/v1/messages/unreadOkunmamış ekip cevapları: [{ kind, code, count }]
GET POST/mobile/v1/reviews/{transfer|tour}/{code}Değerlendirme formu (kriterler, mevcut yorum) / kaydet { comment, scores: [{ criterionId, stars }] }. Yalnızca tamamlanan rezervasyon; değilse 422 NotAllowed
POST/mobile/v1/bookings/quoteÖdeme adımı önizlemesi: { priceId, currency, hasReturn, passengerCount, couponCode, useWallet } → ara toplam, kupon indirimi, cüzdan, ödenecek tutar, kupon red nedeni (couponRejection), cüzdan bakiyesi. Rezervasyonla aynı hesap
GET/mobile/v1/me/walletSadakat cüzdanı: bakiye (EUR), kazanç oranı ve hareketler (Earned, Spent, Refunded, Expired, Adjustment, ReviewReward)
GET/mobile/v1/tours/{tourId}/request-availability?date&adults&childAgesTarih online satılamıyorsa talep gönderilebilir mi: allowed, block (BookableOnline, TooLate, NotAvailable), leadHours
POST/mobile/v1/tour-requestsTur talebi (fiyat / kontenjan tutulmaz; ekip e-postayla teklif gönderir) → 201 requestCode. 422 reason: InvalidName, InvalidEmail, InvalidPhone, TooLong, BookableOnline, TooLate (leadHours), NotAvailable

Dil: uygulama her isteğe X-App-Language: tr|en|de|es|fr başlığını ekler; sunucunun gönderdiği e-postalar (doğrulama kodu, şifre sıfırlama, talep onayı) bu dilde gider.

Uygulama bağlantıları: site /.well-known/apple-app-site-association (Apple Team ID + Bundle ID: Admin → Ayarlar → Apple ile Giriş) ve /.well-known/assetlinks.json (paket adı + imza SHA-256: Admin → Mobil Uygulama → Sürüm ayarları) dosyalarını yayınlar. E-postadaki rezervasyon ve değerlendirme bağlantıları uygulama kuruluysa uygulamada açılır.

Hız sınırı: uygulama her isteğe X-Installation-Id: <installationId> başlığını ekler. Giriş yapmamış mobil istekler IP yerine kurulum başına sınırlanır (dakikada 120; aynı IP için toplam 600 üst sınır). Başlık yoksa IP başına dakikada 30 geçerlidir.

Kurulum ve bildirimler: uygulama ilk açılışta bir installationId (GUID) üretip güvenli depoda saklar. Push token Firebase'den (FCM) alınır, iOS'ta da FCM token'ı gönderilir. Admin → Mobil Uygulama ekranı bu kayıtlarla hangi sürümde kimlerin olduğunu gösterir ve bildirim gönderir. Bildirimin data.url alanı uygulama içi adrestir (ör. /tours/…) ya da https bağlantısıdır.

Ödeme: rezervasyon yanıtındaki payment.url adresini uygulama içi tarayıcıda açın; müşteri kart, ön ödeme ya da nakit seçer. Durum payment.status alanındadır: awaiting_payment, paid, deposit_paid, pay_driver, refunded, none. Turda nakit seçilmişse pay_driver yerine pay_on_tour gelir (ücret turda ödenir).

Turlar

Akış: suggest ile şehir ya da kategori seçilir → tours listesi → tours/{id} detayı → quote ile kesin fiyat → tour-bookings. Fiyat her zaman sunucuda hesaplanır; rezervasyon da quote ile aynı hesabı kullanır. Tarih verilmezse bugün (Türkiye saati) kullanılır. Dil: en, tr, de, fr, es; tur o dilde yayında değilse İngilizcesi döner (fallbackCulture: "en").

Rezervasyonda tur birden çok kalkış saatine sahipse startTime (HH:mm), birden çok rehber diline sahipse guideLanguage zorunludur. Alış noktası olan turda pickupRegionId ya da pickupAddress verilmelidir. Ödenmemiş tur rezervasyonu kontenjanda 10 dakika yer tutar. 422 nedenleri: NotAvailable, InvalidPax, Closed, OverCapacity (remainingCapacity), TooLate, NoPrice, InvalidName, InvalidEmail, InvalidPhone, InvalidStartTime, InvalidGuideLanguage, InvalidPickup, TooLong, Busy (aynı anda başka rezervasyon işleniyor, tekrar deneyin), TooManyPending (müşterinin ödenmemiş 3 tur rezervasyonu var; birini ödeyin ya da 10 dakika bekleyin).

Uç nokta listesi (Partner API)

Uç noktaAçıklama
GET/v1/meHesap bilgisi ve mod
GET/v1/locations · /v1/locations/{id}/destinationsKonumlar
POST/v1/quotesTeklif (30 dk)
POST/v1/bookingsRezervasyon aç
GET/v1/bookings · /v1/bookings/{code}Listele / getir
POST/v1/bookings/{code}/cancelİptal
POST/v1/bookings/{code}/payments/cardYolcunun kartıyla ödeme (kart formu sizin sitenizde)
GET/v1/bookings/{code}/payments/paypalPayPal JS SDK bilgisi (client id, para birimi, tutar)
POST/v1/bookings/{code}/payments/paypal/orderPayPal order açma (butonun createOrder'ı)
POST/v1/bookings/{code}/payments/paypal/capturePayPal capture (butonun onApprove'u), idempotent
POST/v1/bookings/{code}/simulate-paymentSandbox ödeme taklidi
GET/v1/account · /v1/account/statementCari hesap
POST/v1/auth/login · /refresh · /logoutAcenta kullanıcı token'ı

Sorularınız ve canlıya geçiş için: support@citytransferturkey.com