HT Transportation API Dokümantasyonu

Şehirlerarası otobüs yönetim sistemi için RESTful API referans rehberi. Tüm endpoint'ler, istek/yanıt örnekleri ve iş kuralları bu sayfada yer almaktadır.

Giriş

Base URL

http://localhost:8080/api/v1/

Genel Kurallar

Başarılı Yanıt Formatı

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Örnek Kayıt"
  }
}

Hata Yanıt Formatı

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Kayıt bulunamadı"
  }
}

Validasyon Hatası Formatı

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Girdi doğrulama hatası",
    "details": [
      {
        "field": "email",
        "message": "Geçerli bir e-posta adresi giriniz"
      },
      {
        "field": "password",
        "message": "Şifre en az 8 karakter olmalıdır"
      }
    ]
  }
}

Kimlik Doğrulama

JWT tabanlı kimlik doğrulama sistemi. Access token süresi 15 dakika, refresh token süresi 7 gündür.

POST /api/v1/auth/login

Kullanıcı girişi yapar ve token çifti döndürür.

Yetki: Herkese açık

İstek:

curl -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@ht.com",
    "password": "Admin123!"
  }'

Yanıt (200):

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
    "expires_in": 900,
    "token_type": "Bearer",
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "admin@ht.com",
      "first_name": "Admin",
      "last_name": "User",
      "role": "system_admin",
      "agency_id": null
    }
  }
}

POST /api/v1/auth/refresh

Refresh token kullanarak yeni access token alır.

Yetki: Herkese açık

İstek:

curl -X POST http://localhost:8080/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "dGhpcyBpcyBhIHJlZnJl..."
  }'

Yanıt (200):

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "yenilenmis_refresh_token...",
    "expires_in": 900,
    "token_type": "Bearer"
  }
}

GET /api/v1/auth/me

Mevcut oturumdaki kullanıcı bilgilerini döndürür.

Yetki: Tüm oturum açmış kullanıcılar

İstek:

curl http://localhost:8080/api/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Yanıt (200):

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "admin@ht.com",
    "first_name": "Admin",
    "last_name": "User",
    "role": "system_admin",
    "agency_id": null,
    "created_at": "2026-01-15T10:30:00Z"
  }
}

POST /api/v1/users

Yeni kullanıcı oluşturur.

Yetki: user.create

İstek:

curl -X POST http://localhost:8080/api/v1/users \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "personel@ht.com",
    "password": "Sifre123!",
    "first_name": "Ahmet",
    "last_name": "Yılmaz",
    "role": "central_staff"
  }'

GET /api/v1/users

Kullanıcı listesini döndürür.

Yetki: user.read

İstek:

curl http://localhost:8080/api/v1/users \
  -H "Authorization: Bearer <token>"

Güzergah

Şehirlerarası güzergah ve durak yönetimi. Her güzergah birden fazla durak içerebilir ve durakların biniş/iniş özellikleri ayrı ayrı tanımlanır.

POST /api/v1/routes

Yeni güzergah ve durakları oluşturur.

Yetki: route.create

İstek:

curl -X POST http://localhost:8080/api/v1/routes \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "İstanbul - Ankara",
    "origin_city": "İstanbul",
    "destination_city": "Ankara",
    "distance_km": 450,
    "duration_minutes": 360,
    "base_price_kurus": 35000,
    "stops": [
      {
        "stop_name": "İstanbul Otogar",
        "city": "İstanbul",
        "district": "Bayrampaşa",
        "is_boarding": true,
        "is_dropoff": false,
        "stop_order": 1
      },
      {
        "stop_name": "Bolu Dinlenme",
        "city": "Bolu",
        "district": "Merkez",
        "is_boarding": true,
        "is_dropoff": true,
        "stop_order": 2
      },
      {
        "stop_name": "Ankara AŞTİ",
        "city": "Ankara",
        "district": "Yenimahalle",
        "is_boarding": false,
        "is_dropoff": true,
        "stop_order": 3
      }
    ]
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "İstanbul - Ankara",
    "origin_city": "İstanbul",
    "destination_city": "Ankara",
    "distance_km": 450,
    "duration_minutes": 360,
    "base_price_kurus": 35000,
    "is_active": true,
    "stops": [
      {
        "id": "s1000000-0000-0000-0000-000000000001",
        "stop_name": "İstanbul Otogar",
        "city": "İstanbul",
        "district": "Bayrampaşa",
        "is_boarding": true,
        "is_dropoff": false,
        "stop_order": 1
      },
      {
        "id": "s1000000-0000-0000-0000-000000000002",
        "stop_name": "Bolu Dinlenme",
        "city": "Bolu",
        "district": "Merkez",
        "is_boarding": true,
        "is_dropoff": true,
        "stop_order": 2
      },
      {
        "id": "s1000000-0000-0000-0000-000000000003",
        "stop_name": "Ankara AŞTİ",
        "city": "Ankara",
        "district": "Yenimahalle",
        "is_boarding": false,
        "is_dropoff": true,
        "stop_order": 3
      }
    ],
    "created_at": "2026-01-20T09:00:00Z"
  }
}

GET /api/v1/routes

Tüm güzergahları listeler.

Yetki: route.read

İstek:

curl http://localhost:8080/api/v1/routes \
  -H "Authorization: Bearer <token>"

GET /api/v1/routes/:id

Belirli bir güzergahın detayını duraklar ile birlikte döndürür.

Yetki: route.read

İstek:

curl http://localhost:8080/api/v1/routes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Authorization: Bearer <token>"

Koltuk Düzeni

Araç koltuk düzeni şablonları. 2+1, 2+2 gibi farklı konfigürasyon tipleri desteklenir. Her koltuk satır, sütun ve tip bilgisi ile tanımlanır.

POST /api/v1/seat-layouts

Yeni koltuk düzeni oluşturur.

Yetki: seat_layout.create

İstek:

curl -X POST http://localhost:8080/api/v1/seat-layouts \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "2+1 Standart",
    "layout_type": "2+1",
    "total_seats": 40,
    "column_count": 3,
    "seats": [
      {"seat_number": 1, "row": 1, "column": 0, "seat_type": "standard"},
      {"seat_number": 2, "row": 1, "column": 1, "seat_type": "standard"},
      {"seat_number": 3, "row": 1, "column": 2, "seat_type": "standard"}
    ]
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "name": "2+1 Standart",
    "layout_type": "2+1",
    "total_seats": 40,
    "column_count": 3,
    "is_active": true,
    "created_at": "2026-01-20T10:00:00Z"
  }
}

GET /api/v1/seat-layouts

Tüm koltuk düzenlerini listeler.

Yetki: seat_layout.read

İstek:

curl http://localhost:8080/api/v1/seat-layouts \
  -H "Authorization: Bearer <token>"

GET /api/v1/seat-layouts/:id

Belirli bir koltuk düzeninin detayını döndürür.

Yetki: seat_layout.read

İstek:

curl http://localhost:8080/api/v1/seat-layouts/b2c3d4e5-f6a7-8901-bcde-f12345678901 \
  -H "Authorization: Bearer <token>"

Araç

Araç filosu yönetimi. Her araç bir koltuk düzenine bağlanır ve aktif/pasif durumu yönetilebilir.

POST /api/v1/vehicles

Yeni araç oluşturur.

Yetki: vehicle.create

İstek:

curl -X POST http://localhost:8080/api/v1/vehicles \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "plate_number": "34 HT 001",
    "brand": "Mercedes",
    "model": "Travego",
    "year": 2023,
    "seat_layout_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "plate_number": "34 HT 001",
    "brand": "Mercedes",
    "model": "Travego",
    "year": 2023,
    "seat_layout_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "is_active": true,
    "created_at": "2026-01-20T11:00:00Z"
  }
}

GET /api/v1/vehicles

Tüm araçları listeler.

Yetki: vehicle.read

İstek:

curl http://localhost:8080/api/v1/vehicles \
  -H "Authorization: Bearer <token>"

GET /api/v1/vehicles/:id

Belirli bir aracın detayını döndürür.

Yetki: vehicle.read

İstek:

curl http://localhost:8080/api/v1/vehicles/c3d4e5f6-a7b8-9012-cdef-123456789012 \
  -H "Authorization: Bearer <token>"

Sefer

Sefer planlama, arama ve durum yönetimi. Sefer oluşturulduğunda segment bazlı koltuk envanteri otomatik üretilir.

GET /api/v1/trip-search

Halka açık sefer arama. Kimlik doğrulama gerektirmez.

Yetki: Herkese açık (no auth)

ParametreTipZorunluAçıklama
from_citystringEvetKalkış şehri
to_citystringEvetVarış şehri
departure_datestringEvetTarih (YYYY-MM-DD)

İstek:

curl "http://localhost:8080/api/v1/trip-search?from_city=Istanbul&to_city=Ankara&departure_date=2026-03-15"

Yanıt (200):

{
  "success": true,
  "data": [
    {
      "id": "d4e5f6a7-b8c9-0123-def0-234567890123",
      "route_name": "İstanbul - Ankara",
      "departure_time": "2026-03-15T08:00:00Z",
      "arrival_time": "2026-03-15T14:00:00Z",
      "vehicle_plate": "34 HT 001",
      "base_price_kurus": 35000,
      "available_seats": 32,
      "total_seats": 40,
      "status": "scheduled",
      "boarding_stops": [
        {
          "stop_id": "s1000000-0000-0000-0000-000000000001",
          "stop_name": "İstanbul Otogar",
          "city": "İstanbul"
        }
      ],
      "dropoff_stops": [
        {
          "stop_id": "s1000000-0000-0000-0000-000000000003",
          "stop_name": "Ankara AŞTİ",
          "city": "Ankara"
        }
      ]
    }
  ]
}

POST /api/v1/trips

Yeni sefer oluşturur. Segment ve koltuk envanteri otomatik üretilir.

Yetki: trip.create

İstek:

curl -X POST http://localhost:8080/api/v1/trips \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "route_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "vehicle_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "departure_time": "2026-03-15T08:00:00Z",
    "arrival_time": "2026-03-15T14:00:00Z",
    "base_price_kurus": 35000
  }'

GET /api/v1/trips/:id

Sefer detayını döndürür.

Yetki: trip.read

İstek:

curl http://localhost:8080/api/v1/trips/d4e5f6a7-b8c9-0123-def0-234567890123 \
  -H "Authorization: Bearer <token>"

GET /api/v1/trips/:id/seats

Seferin koltuk durumlarını döndürür (müsait, satılmış, rezerve).

Yetki: trip.read

İstek:

curl http://localhost:8080/api/v1/trips/d4e5f6a7-b8c9-0123-def0-234567890123/seats \
  -H "Authorization: Bearer <token>"

GET /api/v1/trip-seats

Sefer koltuk durumlarını query parametresi ile sorgular.

Yetki: trip.read

ParametreTipZorunluAçıklama
trip_idUUIDEvetSefer ID

İstek:

curl "http://localhost:8080/api/v1/trip-seats?trip_id=d4e5f6a7-b8c9-0123-def0-234567890123" \
  -H "Authorization: Bearer <token>"

PUT /api/v1/trips/:id/status

Sefer durumunu günceller.

Yetki: trip.create

İstek:

curl -X PUT http://localhost:8080/api/v1/trips/d4e5f6a7-b8c9-0123-def0-234567890123/status \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "boarding"
  }'

Yanıt (200):

{
  "success": true,
  "data": {
    "id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "status": "boarding",
    "updated_at": "2026-03-15T07:45:00Z"
  }
}

Yolcu

TC Kimlik No bazlı yolcu kayıt sistemi. Yolcu bilgileri bilet ve rezervasyon işlemlerinde kullanılır.

POST /api/v1/passengers

Yeni yolcu kaydeder.

Yetki: passenger.create

İstek:

curl -X POST http://localhost:8080/api/v1/passengers \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "tc_no": "12345678901",
    "ad": "Mehmet",
    "soyad": "Demir",
    "cinsiyet": "male",
    "telefon": "05321234567",
    "email": "mehmet@example.com",
    "dogum_tarihi": "1990-05-15"
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
    "tc_no": "12345678901",
    "ad": "Mehmet",
    "soyad": "Demir",
    "cinsiyet": "male",
    "telefon": "05321234567",
    "email": "mehmet@example.com",
    "dogum_tarihi": "1990-05-15",
    "created_at": "2026-01-25T14:00:00Z"
  }
}

GET /api/v1/passengers/:id

Yolcu detayını döndürür.

Yetki: passenger.read

İstek:

curl http://localhost:8080/api/v1/passengers/e5f6a7b8-c9d0-1234-ef01-345678901234 \
  -H "Authorization: Bearer <token>"

GET /api/v1/passenger-search

TC Kimlik No ile yolcu arar.

Yetki: passenger.search

ParametreTipZorunluAçıklama
tc_nostringEvetTC Kimlik Numarası

İstek:

curl "http://localhost:8080/api/v1/passenger-search?tc_no=12345678901" \
  -H "Authorization: Bearer <token>"

Acente

Acente ağı yönetimi. Her acentenin kendine ait şubeleri, kullanıcıları ve kontör hesabı vardır. Acente kullanıcıları yalnızca kendi acentesinin verilerini görebilir.

POST /api/v1/agencies

Yeni acente oluşturur.

Yetki: agency.create

İstek:

curl -X POST http://localhost:8080/api/v1/agencies \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Anadolu Tur",
    "code": "ANT",
    "tax_no": "1234567890",
    "tax_office": "Kadıköy VD",
    "address": "Kadıköy, İstanbul",
    "phone": "02161234567",
    "email": "info@anadolutur.com",
    "commission_rate_pct": 8.0
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "f6a7b8c9-d0e1-2345-f012-456789012345",
    "name": "Anadolu Tur",
    "code": "ANT",
    "tax_no": "1234567890",
    "tax_office": "Kadıköy VD",
    "is_active": true,
    "created_at": "2026-01-25T15:00:00Z"
  }
}

GET /api/v1/agencies

Tüm acenteleri listeler.

Yetki: agency.read

İstek:

curl http://localhost:8080/api/v1/agencies \
  -H "Authorization: Bearer <token>"

GET /api/v1/agencies/:id

Acente detayını döndürür.

Yetki: agency.read

İstek:

curl http://localhost:8080/api/v1/agencies/f6a7b8c9-d0e1-2345-f012-456789012345 \
  -H "Authorization: Bearer <token>"

POST /api/v1/agency-branches/:id

Acenteye yeni şube ekler.

Yetki: branch.create

İstek:

curl -X POST http://localhost:8080/api/v1/agency-branches/f6a7b8c9-d0e1-2345-f012-456789012345 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Kadıköy Şubesi",
    "address": "Kadıköy Meydan No:5",
    "phone": "02161234568"
  }'

Kontör

Acente ön ödemeli bakiye sistemi. Bilet satışı sırasında kontör bakiyesinden otomatik düşüm yapılır, iptal durumunda iade edilir. Tüm işlemler tam denetim izi ile kayıt altına alınır.

GET /api/v1/kontor/:agency_id

Acentenin kontör bakiyesini döndürür.

Yetki: kontor.read + acente kapsamında erişim

İstek:

curl http://localhost:8080/api/v1/kontor/f6a7b8c9-d0e1-2345-f012-456789012345 \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "agency_id": "f6a7b8c9-d0e1-2345-f012-456789012345",
    "agency_name": "Anadolu Tur",
    "balance_kurus": 5000000,
    "credit_limit_kurus": 1000000,
    "available_kurus": 6000000,
    "updated_at": "2026-02-01T10:30:00Z"
  }
}

POST /api/v1/kontor/:agency_id/load

Acenteye kontör yükler.

Yetki: kontor.load

İstek (50.000 TL yükleme):

curl -X POST http://localhost:8080/api/v1/kontor/f6a7b8c9-d0e1-2345-f012-456789012345/load \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_kurus": 5000000,
    "description": "Şubat 2026 kontör yükleme"
  }'

Yanıt (200):

{
  "success": true,
  "data": {
    "transaction_id": "t1000000-0000-0000-0000-000000000001",
    "agency_id": "f6a7b8c9-d0e1-2345-f012-456789012345",
    "type": "load",
    "amount_kurus": 5000000,
    "balance_after_kurus": 10000000,
    "description": "Şubat 2026 kontör yükleme",
    "created_at": "2026-02-01T11:00:00Z"
  }
}

GET /api/v1/kontor/:agency_id/transactions

Acentenin kontör işlem geçmişini listeler.

Yetki: kontor.transactions + acente kapsamında erişim

İstek:

curl http://localhost:8080/api/v1/kontor/f6a7b8c9-d0e1-2345-f012-456789012345/transactions \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": [
    {
      "id": "t1000000-0000-0000-0000-000000000001",
      "type": "load",
      "amount_kurus": 5000000,
      "balance_after_kurus": 10000000,
      "description": "Şubat 2026 kontör yükleme",
      "reference_type": null,
      "reference_id": null,
      "created_at": "2026-02-01T11:00:00Z"
    },
    {
      "id": "t1000000-0000-0000-0000-000000000002",
      "type": "debit",
      "amount_kurus": -35000,
      "balance_after_kurus": 9965000,
      "description": "Bilet satışı - PNR: HT7A3BX2",
      "reference_type": "ticket",
      "reference_id": "tk-xxx-xxx",
      "created_at": "2026-02-01T12:15:00Z"
    }
  ]
}

Rezervasyon

Geçici koltuk tutma sistemi. Rezervasyon yapıldığında koltuklar belirli bir süre tutulur ve süre dolunca otomatik olarak serbest bırakılır. Kanal bazlı hold süreleri aşağıdaki gibidir:

KanalKodHold Süresi
Mobil Uygulamamobile10 dakika
Web Acenteweb_agency15 dakika
Çağrı Merkezicall_center60 dakika

POST /api/v1/reservations

Yeni rezervasyon oluşturur.

Yetki: reservation.create

İstek:

curl -X POST http://localhost:8080/api/v1/reservations \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "trip_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "boarding_stop_id": "s1000000-0000-0000-0000-000000000001",
    "dropoff_stop_id": "s1000000-0000-0000-0000-000000000003",
    "channel": "web_agency",
    "passengers": [
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
        "seat_number": 5
      },
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901235",
        "seat_number": 6
      }
    ]
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "r1000000-0000-0000-0000-000000000001",
    "pnr": "HT8K2M5N",
    "trip_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "status": "hold",
    "channel": "web_agency",
    "hold_until": "2026-03-15T07:15:00Z",
    "passengers": [
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
        "seat_number": 5,
        "ad": "Mehmet",
        "soyad": "Demir"
      },
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901235",
        "seat_number": 6,
        "ad": "Ayşe",
        "soyad": "Demir"
      }
    ],
    "created_at": "2026-03-15T07:00:00Z"
  }
}

GET /api/v1/reservations

Rezervasyonları listeler.

Yetki: reservation.read

İstek:

curl http://localhost:8080/api/v1/reservations \
  -H "Authorization: Bearer <token>"

GET /api/v1/reservations/:id

Belirli bir rezervasyonun detayını döndürür.

Yetki: reservation.read

İstek:

curl http://localhost:8080/api/v1/reservations/r1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

POST /api/v1/reservation-cancel/:id

Rezervasyonu iptal eder ve koltukları serbest bırakır.

Yetki: reservation.cancel

İstek:

curl -X POST http://localhost:8080/api/v1/reservation-cancel/r1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "id": "r1000000-0000-0000-0000-000000000001",
    "status": "cancelled",
    "cancelled_at": "2026-03-15T07:10:00Z"
  }
}

Biletleme

Bilet kesme, iptal ve yönetim işlemleri. Bilet doğrudan satılabildiği gibi mevcut bir rezervasyondan da dönüştürülerek kesilebilir. Her bilet benzersiz bir PNR kodu alır.

POST /api/v1/tickets

Doğrudan bilet keser (direkt satış).

Yetki: ticket.issue

İstek:

curl -X POST http://localhost:8080/api/v1/tickets \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "trip_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "agency_id": "f6a7b8c9-d0e1-2345-f012-456789012345",
    "channel": "web_agency",
    "boarding_stop_id": "s1000000-0000-0000-0000-000000000001",
    "dropoff_stop_id": "s1000000-0000-0000-0000-000000000003",
    "base_amount_kurus": 35000,
    "total_amount_kurus": 35000,
    "passengers": [
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
        "seat_number": 10
      }
    ]
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "tk-1000000-0000-0000-0000-000000000001",
    "pnr": "HT7A3BX2",
    "trip_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "agency_id": "f6a7b8c9-d0e1-2345-f012-456789012345",
    "status": "issued",
    "channel": "web_agency",
    "base_amount_kurus": 35000,
    "total_amount_kurus": 35000,
    "passengers": [
      {
        "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
        "seat_number": 10,
        "ad": "Mehmet",
        "soyad": "Demir",
        "is_boarded": false
      }
    ],
    "created_at": "2026-02-01T12:15:00Z"
  }
}

GET /api/v1/tickets

Bilet listesini döndürür.

Yetki: ticket.read

İstek:

curl http://localhost:8080/api/v1/tickets \
  -H "Authorization: Bearer <token>"

GET /api/v1/tickets/:id

Bilet detayını döndürür.

Yetki: ticket.read

İstek:

curl http://localhost:8080/api/v1/tickets/tk-1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

GET /api/v1/ticket-by-pnr/:pnr

PNR kodu ile bilet sorgular.

Yetki: ticket.read

İstek:

curl http://localhost:8080/api/v1/ticket-by-pnr/HT7A3BX2 \
  -H "Authorization: Bearer <token>"

POST /api/v1/ticket-from-reservation

Mevcut rezervasyonu bilete dönüştürür.

Yetki: ticket.issue

İstek:

curl -X POST http://localhost:8080/api/v1/ticket-from-reservation \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "reservation_id": "r1000000-0000-0000-0000-000000000001",
    "base_amount_kurus": 35000,
    "total_amount_kurus": 35000
  }'

POST /api/v1/ticket-cancel/:id

Bileti iptal eder. Kalkış saatine kalan süreye göre kademeli iade uygulanır.

Yetki: ticket.cancel

İstek:

curl -X POST http://localhost:8080/api/v1/ticket-cancel/tk-1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Yolcu talebi ile iptal"
  }'

Yanıt (200):

{
  "success": true,
  "data": {
    "id": "tk-1000000-0000-0000-0000-000000000001",
    "pnr": "HT7A3BX2",
    "status": "cancelled",
    "original_amount_kurus": 35000,
    "refund_rate_pct": 80,
    "refund_amount_kurus": 28000,
    "cancel_reason": "Yolcu talebi ile iptal",
    "cancelled_at": "2026-03-14T20:00:00Z"
  }
}

PUT /api/v1/tickets/:id/board/:passenger_id

Yolcunun binişini onaylar.

Yetki: ticket.issue

İstek:

curl -X PUT http://localhost:8080/api/v1/tickets/tk-1000000-0000-0000-0000-000000000001/board/e5f6a7b8-c9d0-1234-ef01-345678901234 \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "passenger_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
    "is_boarded": true,
    "boarded_at": "2026-03-15T07:55:00Z"
  }
}

Partner

Araç ortağı (partner) yönetimi. Partnerler araçlara pay oranı ile atanır. Komisyon ve kesinti tanımları yapılabilir. Hakediş hesaplama bu tanımlara göre çalışır.

POST /api/v1/partners

Yeni partner oluşturur.

Yetki: partner.create

İstek:

curl -X POST http://localhost:8080/api/v1/partners \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "P001",
    "name": "Ali Kaya",
    "partner_type": "individual",
    "commission_rate_pct": 8.0,
    "tax_no": "12345678901",
    "iban": "TR330006100519786457841326"
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "p1000000-0000-0000-0000-000000000001",
    "code": "P001",
    "name": "Ali Kaya",
    "partner_type": "individual",
    "commission_rate_pct": 8.0,
    "tax_no": "12345678901",
    "iban": "TR330006100519786457841326",
    "is_active": true,
    "created_at": "2026-01-28T09:00:00Z"
  }
}

GET /api/v1/partners

Tüm partnerleri listeler.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/partners \
  -H "Authorization: Bearer <token>"

GET /api/v1/partners/:id

Partner detayını döndürür.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

PUT /api/v1/partners/:id

Partner bilgilerini günceller.

Yetki: partner.update

İstek:

curl -X PUT http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ali Kaya Taşımacılık",
    "partner_type": "corporate",
    "commission_rate_pct": 7.5
  }'

POST /api/v1/partners/:id/deductions

Partnere kesinti tanımı ekler.

Yetki: partner.update

İstek:

curl -X POST http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001/deductions \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "deduction_type": "fixed_kurus",
    "name": "Yakıt Kesintisi",
    "value": 250000
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "id": "dd-100000-0000-0000-0000-000000000001",
    "partner_id": "p1000000-0000-0000-0000-000000000001",
    "deduction_type": "fixed_kurus",
    "name": "Yakıt Kesintisi",
    "value": 250000,
    "is_active": true
  }
}

PUT /api/v1/partners/:id/deductions/:did

Kesinti tanımını günceller.

Yetki: partner.update

İstek:

curl -X PUT http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001/deductions/dd-100000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Yakıt Kesintisi (Güncel)",
    "value": 300000
  }'

DELETE /api/v1/partners/:id/deductions/:did

Kesinti tanımını siler.

Yetki: partner.update

İstek:

curl -X DELETE http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001/deductions/dd-100000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

POST /api/v1/vehicles/:id/partners

Araca partner atar (pay oranı ile).

Yetki: partner.update

İstek:

curl -X POST http://localhost:8080/api/v1/vehicles/c3d4e5f6-a7b8-9012-cdef-123456789012/partners \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_id": "p1000000-0000-0000-0000-000000000001",
    "share_pct": 60.0
  }'

GET /api/v1/vehicles/:id/partners

Araca atanmış partnerleri listeler.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/vehicles/c3d4e5f6-a7b8-9012-cdef-123456789012/partners \
  -H "Authorization: Bearer <token>"

DELETE /api/v1/vehicles/:id/partners/:pid

Araçtan partner atamasını kaldırır.

Yetki: partner.update

İstek:

curl -X DELETE http://localhost:8080/api/v1/vehicles/c3d4e5f6-a7b8-9012-cdef-123456789012/partners/p1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

Hakediş

Sefer bazlı otomatik gelir paylaşımı hesaplama, onay akışı, faturalama ve cari hesap takip sistemi.

POST /api/v1/hakedish/calculate/:trip_id

Belirli bir sefer için hakediş hesaplar. Sefer durumu "completed" olmalıdır.

Yetki: hakedish.calculate

İstek:

curl -X POST http://localhost:8080/api/v1/hakedish/calculate/d4e5f6a7-b8c9-0123-def0-234567890123 \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": [
    {
      "id": "hk-100000-0000-0000-0000-000000000001",
      "trip_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
      "partner_id": "p1000000-0000-0000-0000-000000000001",
      "partner_name": "Ali Kaya",
      "trip_revenue_kurus": 10000000,
      "share_pct": 60.0,
      "gross_share_kurus": 6000000,
      "commission_rate_pct": 8.0,
      "commission_kurus": 480000,
      "deductions_kurus": 382800,
      "deduction_details": [
        {"name": "Yakıt Kesintisi", "type": "fixed_kurus", "amount_kurus": 250000},
        {"name": "HGS", "type": "fixed_kurus", "amount_kurus": 50000},
        {"name": "Sigorta", "type": "percentage", "amount_kurus": 82800}
      ],
      "net_amount_kurus": 5137200,
      "status": "calculated",
      "calculated_at": "2026-03-16T10:00:00Z"
    }
  ]
}

GET /api/v1/hakedish/trip/:trip_id

Belirli bir seferin hakediş kayıtlarını döndürür.

Yetki: hakedish.calculate

İstek:

curl http://localhost:8080/api/v1/hakedish/trip/d4e5f6a7-b8c9-0123-def0-234567890123 \
  -H "Authorization: Bearer <token>"

GET /api/v1/hakedish/partner/:partner_id

Belirli bir partnerin tüm hakediş kayıtlarını döndürür.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/hakedish/partner/p1000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer <token>"

PUT /api/v1/hakedish/:id/approve

Hakediş kaydını onaylar.

Yetki: hakedish.approve

İstek:

curl -X PUT http://localhost:8080/api/v1/hakedish/hk-100000-0000-0000-0000-000000000001/approve \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "id": "hk-100000-0000-0000-0000-000000000001",
    "status": "approved",
    "approved_at": "2026-03-16T11:00:00Z",
    "approved_by": "550e8400-e29b-41d4-a716-446655440000"
  }
}

POST /api/v1/hakedish/invoice

Onaylanmış hakediş kayıtları için fatura oluşturur.

Yetki: hakedish.invoice

İstek:

curl -X POST http://localhost:8080/api/v1/hakedish/invoice \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_id": "p1000000-0000-0000-0000-000000000001",
    "entry_ids": [
      "hk-100000-0000-0000-0000-000000000001",
      "hk-100000-0000-0000-0000-000000000002"
    ],
    "period_start": "2026-03-01",
    "period_end": "2026-03-31"
  }'

Yanıt (201):

{
  "success": true,
  "data": {
    "invoice_id": "inv-10000-0000-0000-0000-000000000001",
    "partner_id": "p1000000-0000-0000-0000-000000000001",
    "period_start": "2026-03-01",
    "period_end": "2026-03-31",
    "total_amount_kurus": 10274400,
    "entry_count": 2,
    "status": "invoiced",
    "created_at": "2026-04-01T09:00:00Z"
  }
}

GET /api/v1/partners/:id/current-account

Partnerin cari hesap özetini döndürür.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001/current-account \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "partner_id": "p1000000-0000-0000-0000-000000000001",
    "partner_name": "Ali Kaya",
    "total_earned_kurus": 51372000,
    "total_paid_kurus": 40000000,
    "balance_kurus": 11372000
  }
}

GET /api/v1/partners/:id/current-account/transactions

Partnerin cari hesap hareketlerini listeler.

Yetki: partner.read

İstek:

curl http://localhost:8080/api/v1/partners/p1000000-0000-0000-0000-000000000001/current-account/transactions \
  -H "Authorization: Bearer <token>"

Raporlama

12 farklı aggregate rapor endpoint'i. Tüm raporlar start_date ve end_date query parametreleri ile tarih aralığı filtrelemeyi destekler.

MetodEndpointYetkiAçıklama
GET /api/v1/reports/dashboard report.dashboard Genel özet dashboard
GET /api/v1/reports/revenue/daily report.revenue Günlük gelir raporu
GET /api/v1/reports/revenue/by-agency report.revenue Acente bazlı gelir
GET /api/v1/reports/revenue/by-route report.revenue Güzergah bazlı gelir
GET /api/v1/reports/revenue/by-channel report.revenue Kanal bazlı gelir
GET /api/v1/reports/tickets/status report.dashboard Bilet durum dağılımı
GET /api/v1/reports/trips/occupancy report.trips Sefer doluluk oranı
GET /api/v1/reports/trips/status report.trips Sefer durum dağılımı
GET /api/v1/reports/hakedish/by-partner report.hakedish Partner bazlı hakediş
GET /api/v1/reports/hakedish/status report.hakedish Hakediş durum dağılımı
GET /api/v1/reports/ledger/summary report.revenue Muhasebe defteri özeti
GET /api/v1/reports/kontor/summary report.revenue Kontör özet raporu

Örnek: Dashboard Raporu

İstek:

curl "http://localhost:8080/api/v1/reports/dashboard?start_date=2026-03-01&end_date=2026-03-31" \
  -H "Authorization: Bearer <token>"

Yanıt (200):

{
  "success": true,
  "data": {
    "period": {
      "start_date": "2026-03-01",
      "end_date": "2026-03-31"
    },
    "tickets": {
      "total_issued": 1250,
      "total_cancelled": 87,
      "total_revenue_kurus": 43750000,
      "avg_ticket_price_kurus": 35000
    },
    "trips": {
      "total_scheduled": 180,
      "total_completed": 165,
      "total_cancelled": 5,
      "avg_occupancy_pct": 72.5
    },
    "reservations": {
      "total_created": 890,
      "total_converted": 720,
      "total_expired": 120,
      "conversion_rate_pct": 80.9
    },
    "kontor": {
      "total_loaded_kurus": 50000000,
      "total_spent_kurus": 43750000,
      "total_refunded_kurus": 2436000
    },
    "hakedish": {
      "total_calculated_kurus": 26250000,
      "total_approved_kurus": 22000000,
      "pending_approval_count": 15
    }
  }
}

Roller & İzinler

Sistem 6 kullanıcı rolü ve modül bazlı yetkilendirme ile çalışır. Aşağıdaki tabloda her rolün hangi modül işlemlerine erişimi olduğu gösterilmektedir.

Rol Kullanıcı Güzergah Araç Sefer Yolcu Acente Kontör Rezervasyon Bilet Partner Hakediş Raporlama
system_admin
central_staff
call_center
agency_admin
agency_user
driver

Not: agency_admin ve agency_user rolleri yalnızca kendi acentelerine ait verileri görebilir ve işlem yapabilir (acente veri izolasyonu). driver rolü yalnızca kendi seferlerini salt okunur olarak görüntüleyebilir.

İş Kuralları

Bilet İptal ve İade Tablosu

Kalkış saatine kalan süreye göre kademeli iade oranları uygulanır:

Kalkışa Kalan Süreİade OranıÖrnek (1.000 TL Bilet)
24 saat ve üzeri %100 1.000 TL iade
12 - 24 saat arası %80 800 TL iade
3 - 12 saat arası %50 500 TL iade
3 saatten az İptal engellenir İptal yapılamaz

Cinsiyet Bitişiklik Kuralı

Türk otobüs taşımacılığı düzenlemelerine uygun olarak farklı cinsiyetteki yolcular yan yana oturtulmaz. Kural detayları:

Rezervasyon Hold Süreleri

Kanal bazlı geçici koltuk tutma süreleri:

KanalHold SüresiKullanım Senaryosu
mobile10 dakikaMobil uygulama üzerinden hızlı satış
web_agency15 dakikaAcente web paneli üzerinden satış
call_center60 dakikaÇağrı merkezi yolcu ile görüşme süresi

Hold süresi dolduğunda rezervasyon otomatik olarak expired durumuna geçer ve koltuklar serbest bırakılır.

Sefer Durum Geçişleri

Seferler aşağıdaki durum akışını takip eder:

  scheduled ──────► boarding ──────► in_transit ──────► completed
      │                 │
      │                 │
      ▼                 ▼
  cancelled         cancelled
Mevcut DurumGeçiş Yapılabilir
scheduledboarding, cancelled
boardingin_transit, cancelled
in_transitcompleted
completedGeçiş yapılamaz (final durum)
cancelledGeçiş yapılamaz (final durum)

Hakediş Hesaplama Formülü

Sefer tamamlandığında partnerlerin net hakedişleri aşağıdaki formül ile hesaplanır:

Sefer Geliri (toplam bilet satışı)
    |
    ├── Ortak Brüt Payı = Sefer Geliri x Pay Oranı (%)
    |
    ├── Komisyon = Brüt Pay x Komisyon Oranı (%)
    |
    ├── Kesintiler (toplam)
    |     ├── Sabit kesintiler (fixed_kurus): doğrudan düşülür
    |     └── Yüzdelik kesintiler (percentage): Brüt Pay üzerinden hesaplanır
    |
    └── Net Hakediş = Brüt Pay - Komisyon - Toplam Kesintiler

Örnek hesaplama:

KalemDeğer
Sefer Geliri100.000 TL
Ortak Pay Oranı%60
Brüt Pay60.000 TL
Komisyon (%8)-4.800 TL
Yakıt Kesintisi (sabit)-2.500 TL
HGS Kesintisi (sabit)-500 TL
Sigorta (%1.38 x Brüt)-828 TL
Net Hakediş51.372 TL