API Dokümantasyonu
Mobil cihazlardan konum verisi toplayan ve takip eden modern bir RESTful API servisidir. Gerçek zamanlı takip, geçmiş veriler ve kullanıcı yönetimi için kapsamlı endpoint'ler sunar.
📋 Genel Bakış
TraxNavi API, mobil cihazlardan (iOS ve Android) gelen konum verilerini işler ve saklar. API, RESTful prensiplere göre tasarlanmıştır.
Temel Bilgiler
| Temel URL | https://traxnavi.com/api/v1 |
|---|---|
| Sürüm | v1 |
| Format | JSON |
| Kimlik | Laravel Sanctum (Bearer Token) |
| CORS | traxops.com, turusatools.com, Mobil Uygulamalar |
Veri Formatı
Tüm endpoint'ler artık standart bir JSON yapısı kullanır.
Standart Başarılı Yanıt:
{
"success": true,
"message": "Optional message",
"data": { ... },
"meta": { ... } // Sayfalama varsa
}
Standart Hata Yanıtı:
{
"success": false,
"message": "Error description",
"errors": { ... } // Validation errors
}
⚠️ Validasyon ve Hata Kodları
İstek yükü veya parametreleri geçersiz olduğunda döndürülür. :field alanı beklenen kuralı karşılamıyor. Tam şema için doğrulama bölümüne bakın.
HTTP Durum Kodları
| Kod | Anlam | Kullanım |
|---|---|---|
| 200 | OK | Başarılı (GET/PUT/POST) |
| 207 | Multi-Status | Konum toplu gönderim: kısmi başarı (bazı kayıtlar geçersiz) |
| 401 | Kimlik doğrulanmadı | Eksik/geçersiz token veya hatalı giriş bilgisi |
| 403 | Yasaklandı | Yetkisiz (örn. company_id eşleşmiyor) |
| 404 | Bulunamadı | Kaynak veya endpoint bulunamadı (örn. user_id) |
| 405 | Metoda İzin Verilmiyor | Yanlış HTTP metodu |
| 422 | Doğrulama Başarısız | Validasyon hatası; detaylar errors alanında |
| 429 | Çok Fazla İstek | Rate limit aşıldı |
| 500 | Sunucu Hatası | Beklenmeyen sunucu hatası |
Standart Yanıt Yapısı
Tüm API endpoint'leri aynı JSON zarfını kullanır. success alanı boolean'dır, message açıklama metni içerir ve data (başarılı durumda) veya errors (başarısız) yük detaylarını taşır.
Başarılı Yanıt (200 OK)
{
"success": true,
"message": "Operation description",
"data": { ... }
}
Sayfalı Koleksiyon Yanıtı (200 OK)
{
"success": true,
"message": "...",
"data": [ ... ],
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 50,
"total": 234,
"from": 1,
"to": 50
},
"links": {
"first": "...?page=1",
"last": "...?page=5",
"prev": null,
"next": "...?page=2"
}
}
Hata Yanıt Örnekleri
401 Kimlik Doğrulanmadı
Token gönderilmedi veya süresi doldu.
{
"success": false,
"message": "Unauthenticated"
}
403 Yasak
Yetkisiz erişim (örn. kayıt başka şirkete ait, sürücü başka kullanıcıya erişmeye çalışıyor).
{
"success": false,
"message": "You do not have access to this resource."
}
404 Bulunamadı
Kaynak bulunamadı (model veya endpoint).
{
"success": false,
"message": "Location not found."
}
405 Metoda İzin Verilmiyor
Yanlış HTTP metodu kullanıldı (örn. GET yerine POST).
{
"success": false,
"message": "HTTP method not allowed for this endpoint."
}
422 Doğrulama Başarısız
Gönderilen veri doğrulama kurallarını karşılamıyor. Alan bazlı hata mesajları errors nesnesinde döner.
{
"success": false,
"message": "Validation Failed",
"errors": {
"email": [
"The email field must be a valid email address."
],
"password": [
"The password field is required."
]
}
}
429 Çok Fazla İstek
Rate limit aşıldı. Yanıt başlıklarında Retry-After.
{
"success": false,
"message": "Too many requests. Please slow down."
}
207 Multi-Status (Batch Kısmi Başarı)
Toplu konum gönderiminde bazı kayıtlar başarılı, bazıları hatalı olduğunda döner.
{
"success": true,
"message": "Processed with some errors",
"data": {
"processed_count": 2,
"stored_history_count": 2,
"error_count": 1,
"errors": [
{
"index": 1,
"input_data": { "timestamp": "invalid", ... },
"errors": {
"timestamp": ["The timestamp field must be a valid date."]
}
}
],
"latest_timestamp": "2026-01-06T14:31:40.000Z"
}
}
500 Sunucu Hatası
Beklenmeyen sunucu hatası. Debug modunda debug nesnesi eklenir.
{
"success": false,
"message": "A database error occurred."
}
💡 İpucu: Kısmi başarıda konum batch endpoint'i 207. Tüm kayıtlar geçersizse 422 ve errors her öğe index, errors (alan -> mesajlar) ve input_data.
🔐 Kimlik Doğrulama
💡 Not: API access token + refresh token çifti kullanır.
Access token aldıktan sonra tüm API isteklerinde şunu ekleyin:
Authorization: Bearer {token}
başlığı.
Access Token
API isteklerinde kullanılır.
Token Yenile
Access token yenilemek için kullanılır.
Token Yenileme:
Her yenilemede yeni bir token çifti üretilir ve eski refresh token iptal edilir.
Token Alma
{
"email": "user@example.com",
"password": "your-password"
}
Token Kullanımı
Authorization: Bearer your-token-here
Content-Type: application/json
⚠️ Token Yaşam Döngüsü: Access token 365 gün geçerlidir; süresi dolduğunda
POST /api/v1/refresh
yukarıdaki endpoint'e refresh token göndererek yeni bir çift alabilirsiniz.
Normal kullanımda refresh nadiren gerekir. Login, logout ve şifre sıfırlama işlemlerinde tüm token'lar otomatik iptal edilir.
⚡ İstek Sınırlama
| Endpoint Grubu | Limit | Açıklama |
|---|---|---|
| Giriş | 5 / dk | Brute-force koruması |
| Konumlar (POST) |
Driver: 60/dk Company: 6000/dk |
Rol bazlı ingest limiti |
| Diğer Endpoint'ler |
Driver: 1000/dk Company: 10000/dk |
Genel API kullanımı |
⚠️ Dikkat: Rate limit aşıldığında 429 Too Many Requests
hatası alırsınız.
🔑 Kimlik Doğrulama Endpoint'leri
/api/v1/login
HERKESE AÇIKE-posta ve şifreyi Sanctum erişim belirteci ve yenileme belirteci ile değiştirir. Yenileme belirteci tek kullanımlıktır — her oturum açma (veya şifre değişikliği) bir öncekini iptal eder. Kullanıcının FCM belirteçleri de yeni bir oturum açmada iptal edilir, böylece anlık bildirimler yeni cihazı izler.
İstek Gövdesi
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| string | ✓ | Kullanıcı email adresi (geçerli email formatı) | |
| password | string | ✓ | Kullanıcı şifresi |
| client | string | Hayır | "mobile" veya "web". Mobil uygulama mutlaka "mobile"; göndermeli; sadece driver giriş yapabilir. |
Validasyon Kuralları
| Alan | Kural |
|---|---|
| required, email | |
| password | required, string |
| client | nullable, in:mobile,web |
curl -X POST https://traxnavi.com/api/v1/login \
-H "Content-Type: application/json" \
-d '{
"email": "driver@example.com",
"password": "secret123",
"client": "mobile"
}'
Başarılı Response (200 OK)
{
"success": true,
"message": "Login successful.",
"data": {
"user": {
"id": 1,
"name": "Alex Yilmaz",
"email": "driver@example.com",
"phone": "+905551234567",
"country_code": "TR",
"role": "driver",
"company_id": 1,
"vehicle": "34 ABC 123",
"job_status": "active",
"created_at": "2025-01-01T12:00:00+00:00",
"updated_at": "2025-01-01T12:00:00+00:00"
},
"token": "1|SampleTokenStringHere123456789",
"refresh_token": "a1b2c3d4e5f6...64 karakter random string",
"expires_in": 31536000
}
}
| Alan | Açıklama |
|---|---|
| token | Access token (Bearer olarak kullanılır, 365 gün geçerli) |
| refresh_token | Refresh token (access token yenilemek için, 730 gün geçerli) |
| expires_in | Access token ömrü (saniye cinsinden, 31536000 = 365 gün) |
| country_code | ISO 3166-1 alpha-2 ülke kodu (ör. TR, US, DE) |
Hatalı Response (401)
{
"success": false,
"message": "Invalid credentials."
}
Validasyon Hatası (422)
{
"success": false,
"message": "Validation Failed",
"errors": {
"email": ["The email field must be a valid email address."],
"password": ["The password field is required."]
}
}
⚠️ Not: Login işlemi mevcut tüm access ve refresh token'ları iptal eder, yeni bir çift (access + refresh) oluşturur.
api_docs.store_the refresh_token değerini güvenli bir şekilde saklayın.
/api/v1/forgot-password
HERKESE AÇIKŞifre sıfırlama bağlantısını e-posta adresine gönderin.
İstek Gövdesi
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| string | ✓ | Geçerli email formatı, zorunlu |
Başarılı Yanıt (200)
{
"success": true,
"message": "We have emailed your password reset link.",
"data": null
}
Validasyon Hatası (422)
{
"success": false,
"message": "Validation Failed",
"errors": {
"email": ["The email field is required."]
}
}
Kullanıcı Bulunamadı (400)
{
"success": false,
"message": "We can't find a user with that email address."
}
/api/v1/reset-password
HERKESE AÇIKToken'ı kullanarak şifreyi sıfırlayın.
İstek Gövdesi
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| token | string | ✓ | E-postadaki reset token |
| string | ✓ | Kullanıcı e-posta adresi | |
| password | string | ✓ | Yeni şifre (min. 8 kar.) |
| password_confirmation | string | ✓ | Şifre tekrarı |
Başarılı Yanıt (200)
{
"success": true,
"message": "Your password has been reset.",
"data": null
}
Validasyon Hatası (422)
{
"success": false,
"message": "Validation Failed",
"errors": {
"password": ["The password field must be at least 8 characters."],
"token": ["The token field is required."]
}
}
Geçersiz Token (400)
{
"success": false,
"message": "This password reset token is invalid."
}
/api/v1/refresh
HERKESE AÇIKGeçerli (iptal edilmemiş, süresi dolmamış) bir yenileme belirtecini yeni bir erişim + yenileme belirteci çiftiyle değiştirir. Sağlanan yenileme belirteci atomik olarak iptal edilir — tekrar kullanılması 401 döndürür. Bu uç nokta için Authorization başlığı GEREKMEZ; yenileme belirteci yalnızca istek gövdesinde gönderilir.
İstek Gövdesi
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| refresh_token | string | ✓ | Login'den alınan 64 karakterlik refresh token |
| client | string | Hayır | "mobile" veya "web". Mobil uygulama "mobile". |
curl -X POST https://traxnavi.com/api/v1/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "a1b2c3d4e5f6...64karakter",
"client": "mobile"
}'
Not: Bu endpoint Authorization header gerektirmez. Sadece request body'de refresh token gönderin.
Başarılı Yanıt (200)
{
"success": true,
"message": "Token refreshed successfully.",
"data": {
"user": {
"id": 1,
"name": "Alex Yilmaz",
"email": "driver@example.com",
"phone": "+905551234567",
"country_code": "TR",
"role": "driver",
"company_id": 1,
"vehicle": "34 ABC 123",
"job_status": "active",
"created_at": "2025-01-01T12:00:00+00:00",
"updated_at": "2025-01-01T12:00:00+00:00"
},
"token": "2|NewAccessTokenHere...",
"refresh_token": "x9y8z7w6...yeni 64 karakter",
"expires_in": 31536000
}
}
Geçersiz/Expired Token (401)
{
"success": false,
"message": "Invalid or expired refresh token."
}
🔄 Token Yenileme: Her başarılı refresh'te eski refresh token iptal edilir ve yeni bir çift döner.
Mobil uygulamada her zaman en son alınan refresh_token değerini güvenli bir şekilde saklayın.
/api/v1/logout
KİMLİK DOĞRULAMA GEREKLİMevcut access token'ı ve tüm aktif refresh token'ları iptal ederek çıkış yapar. Sunucu ayrıca kullanıcının tüm FCM cihaz tokenlarını siler; bu nedenle yeni bir token kaydedilene kadar tüm cihazlarda push bildirimleri durur. Çıkış sonrası hiçbir token kullanılamaz; yeniden giriş gerekir.
Örnek İstek
curl -X POST https://traxnavi.com/api/v1/logout \ -H "Authorization: Bearer YOUR_TOKEN_HERE"
Not: Body gerekmez, sadece Authorization header yeterlidir.
Başarılı Yanıt (200)
{
"success": true,
"message": "Logged out successfully.",
"data": null
}
Token Yoksa (401)
{
"success": false,
"message": "Unauthenticated"
}
📍 Konum Endpoint'leri
/api/v1/locations
KİMLİK DOĞRULAMA GEREKLİMobil cihazdan konum verisi gönderin. Üç farklı format desteklenir:
location location wrapper ile (dizi veya tekil nesne), veya wrapper olmadan doğrudan raw array/obje olarak (flutter_background_geolocation v5 uyumlu).
Özellikler
- 3 Format Desteği:
{"location": [...]}wrapper,{"location": {...}}common.messages.batch_max_100 - flutter_background_geolocation v5 Uyumlu: Plugin'in
locationTemplateayarı gerekmeden varsayılan raw formatı doğrudan kabul edilir - Kısmi Başarı: Geçerli veriler işlenir, hatalılar raporlanır.
- En güncel konum otomatik
locationstablosuna kaydedilir - Timestamp Koruması: api_docs.the
locationslocationstablosu sadece gelen veri mevcut kayıttan daha yeni veya eşitse güncellenir. Hem tekil hem batch gönderimlerde geçerlidir. Eski offline/gecikmeli veri gönderimlerinde mevcut güncel konum korunur; yalnızcalocation_historiesgüncellenir. - Tüm konumlar
location_historiestablosuna kaydedilir - Tekil format: Root
timestampvarsalocations.updated_atvelocation_histories.created_at
Lisans bölgesi koordinat kısıtı
Her konum noktası WGS84 doğrulamasından sonra şirket lisans bölgesine göre kontrol edilir. İzinli alan dışındaki noktalar reddedilir (satır bazlı doğrulama hatası) ve locations / location_histories tablolarına yazılmaz. TR lisansları: Türkiye ile listelenen Avrupa, Kafkasya, Orta Asya ve Orta Doğu kara taşıma ülkeleri (ülke AABB sınırları). US lisansları: yalnızca ABD anakarası (Alaska, Hawaii ve Porto Riko kabul edilmez). Reddedilen noktalar sunucuda license_geo.reject olarak loglanır. İstemciler kısmi başarıyı işlemelidir: aynı batch içindeki geçerli satırlar yine de kaydedilir.
Lisans bölgesi dışındaki koordinatlar için örnek satır hatası:
{
"processed_count": 0,
"error_count": 1,
"errors": [
{
"index": 0,
"errors": {
"coords.latitude": ["Koordinatlar TR lisansınız için Türkiye veya izin verilen kara taşımacılığı ülkeleri içinde olmalıdır."],
"coords.longitude": ["Koordinatlar TR lisansınız için Türkiye veya izin verilen kara taşımacılığı ülkeleri içinde olmalıdır."]
}
}
]
}
TR: Koordinatlar TR lisansınız için Türkiye veya izin verilen kara taşımacılığı ülkeleri içinde olmalıdır. · US: Koordinatlar lisans bölgeniz için ABD anakarası (contiguous) içinde olmalıdır (Alaska, Hawaii ve Porto Riko dahil değildir).
Request Body Parametreleri
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| location | array | object | * | Konum dizisi [{...}] veya tekil nesne {...} (Max: 100). Wrapper olmadan da gönderilebilir - aşağıdaki "Raw Format" örneğine bakın. |
| timestamp | string | Opsiyonel | Tekil format için: updated_at ve created_at olarak kullanılır (ISO 8601) |
| user_id | numeric | Opsiyonel | Sayısal kullanıcı ID; yoksa auth kullanıcısı kullanılır. |
| company_id | int | Opsiyonel | Hesabınızdaki şirket ID ile eşleşmeli; aksi halde 403. |
| app_version | string | Opsiyonel | Uygulama versiyonu ( extras.app_version) |
| extras | object | Opsiyonel | İstek kökünde: örn. {"power_save": true}. Konum satırında extras.power_save, yoksa bu değer kullanılır (batch/tekil aynı mantık). |
| extras.power_save | boolean | Opsiyonel | Sadece kök extras; içinde; nullable boolean, doğrulanır. |
Konum objesi validasyon kuralları (DB limitleri)
Hem batch hem tekil format aynı konum objesi validasyon kurallarına tabidir. Her konum elemanı aşağıdaki kurallara uymalıdır. Uymayan kayıtlar errors dizisinde index ile raporlanır (tekil format için index: 0).
| Alan | Kural / Limit |
|---|---|
| timestamp | recorded_at | required (biri), date (ISO 8601) |
| coords.latitude | required, numeric, -90 .. 90 |
| coords.longitude | required, numeric, -180 .. 180 |
| coords.accuracy | nullable, 0 .. 999999.99 |
| coords.speed | nullable, -1 .. 999.99 (-1 = bilinmiyor) |
| coords.heading | nullable, -1 .. 360 (-1 = bilinmiyor) |
| coords.altitude | nullable, -999999.99 .. 999999.99 |
| coords.altitude_accuracy | nullable, -1 .. 999999.99 (-1 = bilinmiyor) |
| coords.speed_accuracy | nullable, -1 .. 999999.99 (-1 = bilinmiyor) |
| odometry | odometer | nullable, 0 .. 9999999999.99 (her iki alan adı da kabul edilir) |
| activity.type | nullable, string max 191 |
| activity.confidence | nullable, integer 0 .. 100 |
| battery.level | nullable, -1 .. 1 (-1 = bilinmiyor, double/float kabul) |
| battery.is_charging | nullable, boolean |
| uuid, event, type | nullable, string max 191 |
| age | nullable, numeric >= 0 (float/int, ör. 0.227) |
| extras | nullable, object (konum satırı içinde) |
| extras.power_save | nullable, boolean - önce bu alan; yoksa kök extras.power_save; her ikisinde de yoksa veya açıkça null, o zaman şu şekilde kaydedilir: power_save: null |
Location Object Yapısı (Dizi Elemanı)
| Alan | Tür | Gerekli | Açıklama |
|---|---|---|---|
| uuid | string | Opsiyonel | Benzersiz ID (max 191) |
| timestamp | recorded_at | string | ✓ (biri) | ISO 8601 (2026-01-06T14:30:00Z) |
| coords | object | ✓ | latitude ve longitude zorunlu; diğerleri yukarıdaki limitlere uymalı |
| is_moving | boolean | Opsiyonel | Hareket durumu |
| odometry | odometer | float | Opsiyonel | Sayaç metre (0 .. 9999999999.99). Her iki alan adı da kabul edilir (SDK v5: odometer) |
| activity | object | Opsiyonel | {type: string max 191, confidence: 0-100} |
| battery | object | Opsiyonel | {level: -1..1 (-1=bilinmiyor, double kabul), is_charging: bool} |
| extras | object | Opsiyonel | Örn. {"power_save": true}. Kök ile aynı anahtarlar extras; satır değeri önceliklidir. |
Örnek Request (Batch / Tekil / Raw)
Batch (Dizi)
{
"location": [
{
"uuid": "A1-B2-C3-D4",
"timestamp": "2026-01-06T14:30:00.000Z",
"coords": {
"latitude": 41.0082,
"longitude": 28.9784,
"accuracy": 5.4,
"speed": 12.5,
"heading": 90.0,
"altitude": 50.0
},
"is_moving": true,
"odometry": 15000.0,
"activity": {"type": "in_vehicle", "confidence": 100},
"battery": {"level": 0.95, "is_charging": false}
},
{
"uuid": "E5-F6-G7-H8",
"timestamp": "2026-01-06T14:30:50.000Z",
"coords": {
"latitude": 41.0090,
"longitude": 28.9790,
"accuracy": 5.2,
"speed": 18.0,
"heading": 92.0,
"altitude": 51.0
},
"is_moving": true,
"odometry": 15200.0,
"activity": {"type": "in_vehicle", "confidence": 100},
"battery": {"level": 0.94, "is_charging": false}
}
],
"user_id": "555",
"company_id": "12",
"app_version": "1.0.0",
"extras": {
"power_save": true
}
}
Tekil Nesne
Kök timestamp -> locations.updated_at ve location_histories.created_at
{
"timestamp": "2026-02-18T10:20:35.238Z",
"app_version": "1.0.0",
"user_id": "4",
"company_id": "1",
"extras": {
"power_save": true
},
"location": {
"mock": true,
"coords": {
"speed_accuracy": 0,
"speed": 33.41,
"longitude": -122.07997503,
"latitude": 37.33492184,
"accuracy": 5,
"altitude": 0,
"heading": 307.97
},
"is_moving": true,
"age": 0.006,
"odometer": 1718302.37,
"uuid": "737D3103-B489-4828-B22F-664136C4E63D",
"activity": {"type": "unknown", "confidence": 0},
"battery": {"level": -1, "is_charging": false},
"recorded_at": "2026-02-18T10:20:35.224Z"
}
}
Raw Format (flutter_background_geolocation v5 uyumlu)
Doğrudan raw array veya tek obje, location wrapper'ı olmadan gönderilebilir.
API otomatik olarak coords alanını algılayıp formatı normalize eder. Plugin tarafında locationTemplate ayarına gerek yoktur.
Tam gövde yalnızca konum dizisi olduğunda kök extras kullanılamaz; şu gibi alanları power_save ilgili konum objesinin içindeki extras ile gönderin veya şu şekilde sarmalayın: {"location": [...], "extras": {...}}.
Raw Array (birden fazla konum)
[
{
"uuid": "A1-B2-C3-D4",
"timestamp": "2026-01-06T14:30:00.000Z",
"coords": {
"latitude": 41.0082,
"longitude": 28.9784,
"accuracy": 5.4,
"speed": 12.5,
"heading": 90.0,
"altitude": 50.0
},
"is_moving": true,
"odometer": 15000.0,
"activity": {"type": "in_vehicle", "confidence": 100},
"battery": {"level": 0.95, "is_charging": false},
"extras": {"power_save": true}
},
{
"uuid": "E5-F6-G7-H8",
"timestamp": "2026-01-06T14:30:50.000Z",
"coords": {
"latitude": 41.0090,
"longitude": 28.9790,
"accuracy": 5.2,
"speed": 18.0,
"heading": 92.0
},
"is_moving": true,
"odometer": 15200.0,
"activity": {"type": "in_vehicle", "confidence": 100},
"battery": {"level": 0.94, "is_charging": false}
}
]
Raw Tek Obje
common.messages.flutter_v5_format
{
"uuid": "737D3103-B489-4828-B22F-664136C4E63D",
"timestamp": "2026-02-18T10:20:35.238Z",
"coords": {
"speed_accuracy": 0,
"speed": 33.41,
"longitude": -122.07997503,
"latitude": 37.33492184,
"accuracy": 5,
"altitude": 0,
"heading": 307.97
},
"is_moving": true,
"age": 0.006,
"odometer": 1718302.37,
"activity": {"type": "unknown", "confidence": 0},
"battery": {"level": -1, "is_charging": false},
"event": "motionchange",
"extras": {"power_save": true}
}
Yanıt Senaryoları
Tümü Başarılı (200 OK)
Tüm konum kayıtları validasyondan geçti ve işlendi.
{
"success": true,
"message": "Locations processed successfully",
"data": {
"processed_count": 2,
"stored_history_count": 2,
"error_count": 0,
"errors": [],
"latest_timestamp": "2026-01-06T14:30:50.000Z"
}
}
Kısmi Başarı (207 Multi-Status)
Bazı kayıtlar hatalı ama en az biri başarılı. Hatalı kayıtlar errors dizisinde raporlanır.
{
"success": true,
"message": "Processed with some errors",
"data": {
"processed_count": 1,
"stored_history_count": 1,
"error_count": 1,
"errors": [
{
"index": 1,
"input_data": {
"timestamp": "not-a-date",
"coords": {"latitude": 41.0}
},
"errors": {
"timestamp": [
"The timestamp field must be a valid date."
],
"coords.longitude": [
"The coords.longitude field is required."
]
}
}
],
"latest_timestamp": "2026-01-06T14:30:00.000Z"
}
}
Tümü Hatalı (422)
Hiçbir kayıt validasyondan geçemedi veya location alanı eksik/yanlış tipte. Tekil format için errors[0] döner.
{
"success": false,
"message": "All location records failed validation",
"errors": {
"processed_count": 0,
"error_count": 2,
"errors": [
{
"index": 0,
"errors": {
"coords.latitude": [
"The coords.latitude field must be between -90 and 90."
]
}
},
{
"index": 1,
"errors": {
"timestamp": ["The timestamp field is required."]
}
}
]
}
}
Tekil Format Validasyon Hatası (422)
Tekil nesne gönderiminde location (örn. eksik koordinatlar), aynı hata yapısı döndürülür index: 0.
{
"success": false,
"message": "All location records failed validation",
"errors": {
"processed_count": 0,
"error_count": 1,
"errors": [
{
"index": 0,
"errors": {
"coords": ["The coords field is required."],
"coords.latitude": ["The coords.latitude field is required."],
"coords.longitude": ["The coords.longitude field is required."]
}
}
]
}
}
user_id Geçersiz (422)
user_id sayısal değil.
{
"success": false,
"message": "user_id must be a numeric value."
}
Kullanıcı Bulunamadı (404)
Belirtilen user_id veritabanında yok.
{
"success": false,
"message": "User with id '999' not found."
}
Şirket Eşleşmiyor (403)
company_id kullanıcının şirketi ile uyuşmuyor.
{
"success": false,
"message": "company_id does not match your account."
}
/api/v1/locations
KİMLİK DOĞRULAMA GEREKLİSürücüler ve İzleyiciler yalnızca kendi kayıtlarını görür; Yöneticiler ve Süper-yöneticiler şirket içindeki herhangi bir kaydı listeleyebilir. Zaman aralığını sınırlamak için :from ve :to (ISO 8601) kullanın. Seyrek segmentler boş bir liste döndürebilir — daha geniş bir pencere deneyin.
{
"success": true,
"message": "Locations retrieved successfully.",
"data": [
{
"id": 1,
"user_id": 1,
"company_id": 1,
"coords": {
"latitude": 41.015137,
"longitude": 28.97953,
"accuracy": 4.8,
"altitude": 52.0,
"heading": 95.0,
"speed": 22.5
},
"activity": {
"type": "in_vehicle",
"confidence": 100
},
"battery": {
"level": 0.94,
"is_charging": false
},
"odometer": 15500.0,
"is_moving": true,
"event": "location",
"uuid": "I9-J0-K1-L2",
"extras": {
"device_id": null,
"app_version": "1.0.0",
"raw_uuid": "I9-J0-K1-L2",
"power_save": true
},
"timestamp": "2026-01-06T14:31:40+00:00",
"updated_at": "2026-01-06T14:31:40+00:00"
}
],
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"total": 234,
"per_page": 50
},
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
}
}
/api/v1/locations/{location}
KİMLİK DOĞRULAMA GEREKLİBelirli bir konumun detaylarını görüntüleyin. Sürücü sadece kendisine ait kaydı, Admin/Viewer şirketindeki herhangi bir kaydı görebilir.
Başarılı Yanıt (200)
{
"success": true,
"message": "Location retrieved successfully.",
"data": {
"id": 1,
"user_id": 1,
"company_id": 1,
"coords": {
"latitude": 41.015137,
"longitude": 28.97953,
"accuracy": 4.8,
"altitude": 52.0,
"heading": 95.0,
"speed": 22.5
},
"activity": {
"type": "in_vehicle",
"confidence": 100
},
"battery": {
"level": 0.94,
"is_charging": false
},
"odometer": 15500.0,
"is_moving": true,
"event": "location",
"uuid": "I9-J0-K1-L2",
"extras": {
"device_id": null,
"app_version": "1.0.0",
"raw_uuid": "I9-J0-K1-L2",
"power_save": true
},
"timestamp": "2026-01-06T14:31:40+00:00",
"updated_at": "2026-01-06T14:31:40+00:00"
}
}
Kayıt Bulunamadı (404)
{
"success": false,
"message": "Location not found."
}
Yetkisiz Erişim (403)
Başka şirkete ait kayıt veya driver başka kullanıcının kaydına erişim.
{
"success": false,
"message": "You do not have access to this resource."
}
📊 Konum Geçmişi Endpoint'leri
💡 Not: Konum geçmişi sadece okunabilir (read-only).
/api/v1/location-histories
KİMLİK DOĞRULAMA GEREKLİRolünüze göre konum geçmişini listeleyin. Sürücü sadece kendi, Admin/Viewer tüm geçmişi görür.
{
"success": true,
"message": "Location histories retrieved successfully.",
"data": [
{
"id": 1,
"user_id": 1,
"company_id": 1,
"coords": {
"latitude": 41.015137,
"longitude": 28.97953,
...
},
"timestamp": "2026-01-06T14:30:50+00:00"
}
],
"meta": {
"current_page": 1,
"last_page": 10,
"total": 500,
"per_page": 50
...
},
"links": { ... }
}
/api/v1/location-histories/{id}
KİMLİK DOĞRULAMA GEREKLİBelirli bir geçmiş kaydının detaylarını görüntüleyin. Sürücü sadece kendisine ait kaydı, Admin/Viewer şirketindeki herhangi bir kaydı görebilir.
Başarılı Yanıt (200)
{
"success": true,
"message": "Location history retrieved successfully.",
"data": {
"id": 42,
"user_id": 1,
"company_id": 1,
"coords": {
"latitude": 41.0082,
"longitude": 28.9784,
"accuracy": 5.4,
"altitude": 50.0,
"heading": 90.0,
"speed": 12.5
},
"activity": {
"type": "in_vehicle",
"confidence": 100
},
"battery": {
"level": 0.95,
"is_charging": false
},
"odometer": 15000.0,
"is_moving": true,
"event": "location",
"uuid": "A1-B2-C3-D4",
"extras": null,
"timestamp": "2026-01-06T14:30:00+00:00"
}
}
Kayıt Bulunamadı (404)
{
"success": false,
"message": "LocationHistory not found."
}
Yetkisiz Erişim (403)
{
"success": false,
"message": "You do not have access to this resource."
}
👤 Kullanıcı Endpoint'leri
/api/v1/user
KİMLİK DOĞRULAMA GEREKLİGiriş yapmış kullanıcının profil bilgilerini görüntüleyin.
{
"success": true,
"message": "User profile retrieved successfully.",
"data": {
"id": 1,
"name": "Alex Yilmaz",
"email": "driver@example.com",
"phone": "+905551234567",
"country_code": "TR",
"vehicle": "34 ABC 123",
"job_status": "active",
"role": "driver",
"company_id": 1,
"created_at": "2025-01-01T10:00:00+00:00",
"updated_at": "2025-01-01T10:00:00+00:00"
}
}
/api/v1/user
KİMLİK DOĞRULAMA GEREKLİKullanıcının profil bilgilerini güncelleyin. Sadece gönderilen alanlar güncellenir (partial update). Şifre güncellemesi için password_confirmation da zorunludur.
Parametreler ve Validasyon
| Parametre | Tür | Gerekli | Kural |
|---|---|---|---|
| name | string | Opsiyonel | common.messages.max_255 |
| string | Opsiyonel | geçerli email, max 255, unique (kendi kaydı hariç) | |
| password | string | Opsiyonel | common.messages.min_8 confirmed zorunlu |
| password_confirmation | string | password varsa ✓ | password ile aynı olmalı |
| phone | string | Opsiyonel | nullable, max 50 |
| vehicle | string | Opsiyonel | nullable, max 255 |
| job_status | string | Opsiyonel | nullable, max 255 |
Örnek İstek
curl -X PUT https://traxnavi.com/api/v1/user \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Ahmet Yilmaz",
"phone": "+905551234567",
"vehicle": "34 XYZ 789"
}'
Başarılı Yanıt (200)
{
"success": true,
"message": "Profile updated successfully.",
"data": {
"id": 1,
"name": "Ahmet Yilmaz",
"email": "driver@example.com",
"phone": "+905551234567",
"country_code": "TR",
"vehicle": "34 XYZ 789",
"job_status": "active",
"company_id": 1,
"role": "driver",
"created_at": "2025-01-01T10:00:00+00:00",
"updated_at": "2026-02-17T15:30:00+00:00"
}
}
Validasyon Hatası (422)
{
"success": false,
"message": "Validation Failed",
"errors": {
"email": [
"The email has already been taken."
],
"password": [
"The password field must be at least 8 characters.",
"The password field confirmation does not match."
]
}
}
🌍 Genel Servisler
/api/v1/revgeo
HERKESE AÇIKKoordinatları açık adrese çevirir (Reverse Geocoding). Önbellek (cache) mekanizması kullanır.
URL Parametreleri
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| lat | float | ✓ | Enlem (-90 .. 90) |
| lng | float | ✓ | Boylam (-180 .. 180) |
| lang | string | Opsiyonel | Dil (örn: tr, en) |
Örnek İstek
GET /api/v1/revgeo?lat=41.0082&lng=28.9784&lang=tr
Başarılı Yanıt (200)
data içinde kısa adres, tam adres ve ülke kodu (ISO 3166) döner. data. Sonuçlar 10 dk önbelleğe alınır.
{
"success": true,
"message": null,
"data": {
"short": "Istanbul, Marmara Region, Turkiye",
"full": "Alemdar Street, Cankurtaran District, Istanbul, Marmara Region, 34110, Turkiye",
"cc": "TR"
}
}
Parametre Eksik (422)
{
"success": false,
"message": "lat and lng parameters are required."
}
Sayısal Değil (422)
{
"success": false,
"message": "lat and lng must be numeric values."
}
Aralık Dışı (422)
{
"success": false,
"message": "lat must be between -90 and 90, lng between -180 and 180."
}
Mesajlaşma API
Admin-driver arası 1-on-1 mesajlaşma. Tüm endpoint'ler auth:sanctum.
Konuşmaları Listele
GET /api/v1/conversations?page=1
Kullanıcının tüm sohbet listesi, son mesaj ve okunmamış sayısı ile birlikte (paginated).
Sohbet Başlat / Bul
POST /api/v1/conversations
Sohbet Detayı + Mesajlar
GET /api/v1/conversations/{id}?page=1
Sohbet detayı ve paginated mesaj listesi (en yenisi önce).
Okundu İşaretle
PUT /api/v1/conversations/{id}/read
Sohbet mesajlarını okundu olarak işaretler (last_read_at = now).
Okunmamış Sayısı
GET /api/v1/conversations/unread-count
Kişiler
GET /api/v1/conversations/contacts
Kullanıcının mesaj gönderebileceği kişilerin listesi. Aynı şirketteki uygun roldeki (admin<->driver) aktif kullanıcıları döner. Silinmiş kullanıcılar listelenmez.
Not: Bu liste yeni sohbet başlatmak için kullanılır. Mevcut sohbetler GET /conversations.
Mesaj Gönder
POST /api/v1/conversations/{id}/messages
Mesaj gönderildiğinde, karşı tarafın tüm cihazlarına otomatik FCM push notification gönderilir. Web panelde WebSocket ile anlık güncellenir.
Mesajı sil
DELETE /api/v1/conversations/{id}/messages/{messageId}
Kullanıcının kendi gönderdiği bir mesajı siler. Sadece mesajı gönderen kişi silebilir.
Hata Durumları
| Kod | Durum |
|---|---|
| 403 | Mesaj bu kullanıcıya ait değil veya sohbete katılımcı değil |
| 404 | Mesaj bu sohbette bulunamadı |
Sohbet Geçmişini Temizle
DELETE /api/v1/conversations/{id}/messages
Bir sohbetteki tüm mesajları kalıcı olarak siler. Sohbetin herhangi bir katılımcısı bu işlemi yapabilir.
Dikkat: Bu işlem geri alınamaz. Sohbetteki tüm mesajlar her iki taraf için de kalıcı olarak silinir. İşlem öncesi kullanıcıdan onay alınması önerilir.
Cihaz Tokenları (FCM)
Push notification almak için cihazın FCM token'ını kaydetme/silme.
Token Kaydet
POST /api/v1/device-tokens
Tek aktif cihaz: TraxNavi her kullanıcı için tek aktif cihaz kuralını uygular. Yeni bir token kaydedildiğinde aynı kullanıcıya ait diğer tüm tokenlar silinir; POST /api/v1/login, POST /api/v1/logout ve şifre sıfırlama işlemlerinde kullanıcının tüm FCM token'ları sunucuda silinir. Mobil uygulama şu endpoint'i çağırmalıdır: POST /api/v1/device-tokens (ve Firebase token'ı yenilediğinde de tekrar) böylece push bildirimleri doğru cihaza yönlenir.
Token geçerliliği: Firebase tarafından invalidTokens veya unknownTokens olarak işaretlenen tokenlar gönderim sonrasında otomatik silinir. Güncel FCM tokenını tekrar kaydetmek push iletimini geri açar.
Token Kaldır (Çıkış)
DELETE /api/v1/device-tokens/{token}
Opsiyoneldir. Uygulama çıkış yapmadan push almayı durdurmak istediğinde kullanışlıdır. Logout uç noktası kullanıcının tüm FCM tokenlarını zaten sildiği için bu çağrı şu uçtan sonra gereksizdir: POST /api/v1/logout.
Cihaz Bilgisi
Sunucuya cihaz bilgilerini ve uygulama izin durumlarını gönderir. Bu endpoint, kimliği doğrulanmış kullanıcının kaydını doğrudan users tablosunda günceller. Uygulama her açılışta (giriş sonrası) ve cihazda herhangi bir izin durumu değiştiğinde çağrılmalıdır.
users tablosunda kolon olarak saklanır (ayrı bir tablo değil). Bu endpoint çağrıldığında kimliği doğrulanmış kullanıcı için şu kolonlar güncellenir:
perm_location←locationperm_background_location←background_locationperm_motion←motionperm_notifications←notificationsperm_battery_optimization←battery_optimizationdevice_platform←platformdevice_brand←device_branddevice_model←device_modelos_version←os_versionapp_version←app_versiondevice_info_updated_at← otomatik olarak geçerli zaman damgasına ayarlanırbackground_zero_since_at← arkaplan izni kapandığında set edilir; tekrar açıldığında temizlenirbackground_zero_last_notified_at← arkaplan izin uyarıları için sunucu tarafından yönetilen hatırlatma zaman damgasıbackground_zero_notify_step← sunucu tarafından yönetilen artan hatırlatma adım sayacı
Cihaz Bilgisini Güncelle
POST /api/v1/device-info
Kimlik: Bearer token gerekli. Kullanıcı tokendan belirlenir — user ID parametresi gerekmez.
| Alan | Tür | Gerekli | DB Kolonu | Açıklama |
|---|---|---|---|---|
location | boolean | Evet | perm_location | Konum izni verilmiş mi |
background_location | boolean | Evet | perm_background_location | Arka plan konum izni verilmiş mi |
motion | boolean | Evet | perm_motion | Hareket/aktivite izni verilmiş mi |
notifications | boolean | Evet | perm_notifications | Bildirim izni verilmiş mi |
battery_optimization | boolean | Evet | perm_battery_optimization | Pil optimizasyonunun devre dışı olup olmadığı (true = devre dışı = iyi) |
platform | string | Evet | device_platform | "android" veya "ios" |
device_brand | string (max 80) | Evet | device_brand | device.brand |
device_model | string (max 80) | Evet | device_model | device.model |
os_version | string (max 80) | Hayır | os_version | device.os_version |
app_version | string (max 80) | Hayır | app_version | device.app_version |
- Başarılı girişten hemen sonra (ilk açılış)
- Kullanıcı herhangi bir cihaz iznini verdiğinde veya iptal ettiğinde
- Uygulama ön plana döndüğünde (arka plandan devam)
- Uygulama güncellemesinden sonra (yeni app_version bildirmek için)
- Tüm izin boolean değerleri her çağrıda üzerine yazılır — her zaman 5 izin değerinin tamamını gönderin.
- api_docs.the
device_info_updated_atzaman damgası sunucu tarafından otomatik ayarlanır. - Bu endpoint yalnızca kimliği doğrulanmış kullanıcıyı (Bearer token ile tanımlanan) günceller. Başka bir kullanıcının izinlerini güncelleyemezsiniz.
- Yanıt, güncellenmiş durumu yansıtan UserResource üzerinden tam kullanıcı objesini döner.
- Sadece rolü şu olan giriş yapmış kullanıcılar için geçerlidir
driver. - Tarih
background_locationdeğeri false olduğunda sunucu, arkaplan izninin ne kadar süredir kapalı olduğunu takip eder. - Hatırlatma kontrolleri sunucuda saatlik çalışır ve sadece kullanıcı bir sonraki eşik saatine geldiğinde gönderim yapılır.
- İlk push hatırlatma 2 saat sonra gönderilir; ardından artan aralıklarla devam eder: 6s, 12s, 20s, 30s, 42s, 56s, 72s, 90s, 110s, 132s, 156s.
- Arkaplan izni kapalı kalırsa hatırlatmalar 1 haftadan (168 saat) sonra durur.
- Arkaplan izni tekrar verilirse hatırlatma durumu bir sonraki device-info çağrısında otomatik sıfırlanır.
- İzin kesintisiz kapalı kalırsa sunucu
background_zero_notify_stepalanını her başarılı hatırlatma gönderiminden sonra artırır. - Aktif cihaz tokenı yoksa, yeni token kaydedilene kadar o kullanıcıya push gönderilemez.
- Hatırlatma mesaj dili kullanıcı locale alanından seçilir (
users.locale); geri dönüş varsayılan uygulama yerel ayarıdır. - Takip, bu endpoint
background_location=false(bu durumu hiç bildirmemiş eski kayıtlar için geriye dönük geçerli değildir). - Push, mesajlaşma ile aynı Android bildirim kanalını kullanır:
messages.
// FCM notification
title: "Background permission off"
body: "Your background location permission is off. Location cannot be sent."
// FCM data payload
{
"type": "background_permission_off",
"user_id": "123"
}📦 Yük Yönetimi (Loads)
Carrier ve broker lisanslı şirketler için yük (load) listeleme, detay, sürücü kabul/red ve paylaşım linki ile yük açma. Tüm load endpoint'leri (by-token hariç) Authorization: Bearer <token> ve check.license.api. GET /loads/by-token/{token} kimlik doğrulama gerektirmez (paylaşım linki / deep link için).
Yükleri Listele
GET /api/v1/loads?page=1&per_page=20&status=...&driver_id=...&start_date=...&end_date=...&search=...
Sürücü: kendine atanmış yükler. Admin (veya diğer roller): şirketin tüm yükleri. Filtreler: status, driver_id, start_date (pickup >=), end_date (pickup <=), search (load_no, rate, notes). Sayfalama: page, per_page (1-100). route_data listede de döner (sadeleştirilmiş geometry).
Yük Detayı
GET /api/v1/loads/{id}
Tek yük detayı; pickup/drop listesi (phone dahil), route_data (harita geometry dahil). Sürücü sadece kendine atanmış yükü görebilir.
Neden hem mileage hem route.summary.distance var?
Aynı alanın kopyası değil — iki farklı kaynak. JSON anahtarı geriye uyumluluk için mileage kalır; sayısal değer loads.distance’tan gelir ve şirket bölgesi biriminde saklanmıştır — API yeniden dönüştürmez.
mileage/dead_head— Yük satırındaki sevkiyat özeti (liste + detay). Web loads.distance (ve dead_head) değerini şirket biriminde (km veya mi) yazar ve loads.distance_unit set eder. API bunu mileage + mileage_unit olarak döner. dead_head tamsayı özet; harita geometrisi/ETA route.deadhead altında (yalnızca detay).route.summary/route.deadhead.summary(+lengthInMeters) — Kayıtlı harita rotasının geometrisi (yalnızca detay). Yüklü mil: route.polyline + route.summary (route_data.routes / totalDistance). Deadhead: route.deadhead (route_data.deadhead; yoksa null). OSRM metre → summary.distance (distance_unit); lengthInMeters SI kalır.distance_unit— distance_unit lisans bölgesinden şirket gösterim birimidir (TR=km, US=mi). mileage_unit yük satırında saklanan birimdir (loads.distance_unit). UI için distance_unit tercih edin; mileage/dead_head değerlerini mileage_unit (yoksa distance_unit) ile etiketleyin.
Liste / ücret özeti → mileage (+ dead_head), etiket için mileage_unit (yoksa distance_unit). Şirket gösterim birimi → distance_unit. Harita → route.polyline + route.summary (yüklü sefer) ve route.deadhead.polyline + route.deadhead.summary (sürücü→ilk pickup). ETA için *.summary.duration_seconds. mileage ile route mesafelerini veya dead_head ile route.deadhead.summary.distance’ı toplamayın.
Yük nesnesi alanları (kaynak → anlam)
| Alan | Kaynak | Açıklama |
|---|---|---|
| id | loads.id | Yük birincil anahtarı. |
| load_no | loads.load_no | Web panelinde girilen yük numarası. |
| rate | loads.rate | Yük ücreti / rate (float). |
| status | loads.status | Makine durumu kodu (draft, available, assigned, accepted, in_progress, completed, …). |
| status_label | API’de üretilir (DB kolonu değil) | status için yerelleştirilmiş etiket (UI). |
| pickup_date | loads.pickup_date | Planlanan yükleme tarihi (Y-m-d) veya null. |
| delivery_date | loads.delivery_date | Planlanan teslim tarihi (Y-m-d) veya null. |
| notes | loads.notes | Sevkiyat notları (serbest metin). |
| distance_unit | companies.license_region → CountryProfile | `km` (TR) veya `mi` (US) — companies.license_region → CountryProfile. mileage, dead_head ve route.*.summary.distance için şirket gösterim birimi; lengthInMeters’a uygulanmaz. |
| mileage | loads.distance — value in mileage_unit | Eski JSON anahtarı (DB/web kolonu loads.distance). Liste/detay kartı mesafesi; şirket bölgesi biriminde saklanır. API dönüştürmez. route’tan bağımsız — route null olsa da gelebilir. |
| mileage_unit | loads.distance_unit | `km` veya `mi` — loads.distance_unit; mileage ve dead_head sayılarının birimi. Normalde distance_unit ile aynıdır; saklanan değeri etiketlerken bunu kullanın. |
| dead_head | loads.dead_head — same unit as mileage | loads.dead_head boş mesafe (mileage / mileage_unit ile aynı birim). Web’de rota veya elle. Harita overlay: route.deadhead (detay); route.deadhead.summary.distance ile toplamayın. |
| driver | users via loads.driver_id | Atanan sürücü özeti (id, name, email, phone) veya null. |
| pickups / drops | load_stops (type) | sequence’e göre duraklar: name, address, city, state, country, phone, lat, lng. |
| documents | load_documents | Yalnızca PDF metadata (byte yok). Binary için /documents/{id}/preview veya /download. |
| document_quota | API’de üretilir (DB kolonu değil) | Yükleme slotları: max = pickup + drop + 1 additional; used/remaining ve slot dolulukları. |
| route | loads.route_data JSON → overlay | Yalnızca detay — loads.route_data’dan harita paketi: yüklü polyline/summary ve isteğe bağlı deadhead overlay. Rota yoksa null. GET /loads listesinde yok. mileage’ın ikinci kopyası değildir. |
| route.polyline | route_data.routes[].geometry | Yüklü pickup→drop yolu için [[lat, lng], …] (yaklaşık 500 noktaya kısaltılabilir). Deadhead içermez. |
| route.summary.lengthInMeters | route_data.totalDistance (SI m) | Motorun kanonik uzunluğu (metre, SI). Hassasiyet için; distance_unit ile dönüşmez. |
| route.summary.travelTimeInSeconds | route_data.totalDuration (s) | OSRM/ORS’tan gelen kanonik süre (saniye, totalDuration). |
| route.summary.distance | API’de üretilir (DB kolonu değil) | lengthInMeters’ın distance_unit’e çevrilmiş hali (harita/ETA). Üst seviye mileage alanının yerine geçmez. |
| route.summary.distance_unit | CountryProfile | `km` (TR) veya `mi` (US) — companies.license_region → CountryProfile. mileage, dead_head ve route.*.summary.distance için şirket gösterim birimi; lengthInMeters’a uygulanmaz. |
| route.summary.duration_seconds | alias of travelTimeInSeconds | travelTimeInSeconds ile aynı — mobil için kısayol alan. |
| route.deadhead | route_data.deadhead → overlay | Sürücü→ilk pickup overlay (route_data.deadhead). summary şekli route.summary ile aynı. Hesaplanmadıysa/kaydedilmediyse null. Ayrı katman — route.polyline’a karıştırılmaz. |
| route.deadhead.polyline | route_data.deadhead.geometry | Deadhead yolu için [[lat, lng], …] (yaklaşık 300 noktaya kısaltılabilir). |
| route.deadhead.summary.* | deadhead.distance / duration (SI) | lengthInMeters’ın distance_unit’e çevrilmiş hali (harita/ETA). Üst seviye mileage alanının yerine geçmez. travelTimeInSeconds ile aynı — mobil için kısayol alan. |
| route.deadhead.origin | deadhead.coordinates + driver_id | Deadhead başlangıç anlık görüntüsü: web rota hesabı sırasındaki atanan sürücü cihazının son konumu (lat/lng + driver_id). source her zaman driver_device (canlı yeniden çekilmez). |
Yükü Kabul Et
POST /api/v1/loads/{id}/accept
Sürücü yükü kabul eder; driver_id atanır, status -> accepted. Yalnızca role=driver kullanıcılar çağırabilir.
Yükü Reddet
POST /api/v1/loads/{id}/decline
Sürücü yükü reddeder; driver_id temizlenir, status -> available. Sadece sürücü rolü.
Yük Durumunu Güncelle
PATCH /api/v1/loads/{id}/status
Yükün status alanını günceller. Sürücü: sadece kendine atanmış yükün durumunu güncelleyebilir. Admin (veya diğer roller): şirketteki herhangi bir yükün durumunu güncelleyebilir.
| Alan | Tür | Gerekli | Açıklama |
|---|---|---|---|
| status | string | Evet | Geçerli değerler: draft, available, assigned, accepted, in_pickup_location, in_progress, in_drop_location, completed, cancelled |
403 - Load does not belong to this user (driver cannot update someone else's load). 404 - Load not found or different company.
Geofence Olayları
POST /api/v1/loads/{id}/geofence-events
Pickup/drop noktası için mobil OS geofence enter/exit olayını bildirir. Şirket admin ve viewer kullanıcılarına uygulama içi (ve tercihe bağlı e-posta/FCM) bildirim oluşturur. Yük durumunu değiştirmez — gerekirse ayrı olarak PATCH /status kullanın.
Kimlik: Yüke atanmış sürücü veya şirket admini. Viewer olay raporlayamaz.
Bu uç nokta yük durumunu güncellemez ve geofence yarıçapını doğrulamaz (yarıçap/dwell mobil istemcide kalır).
| Alan | Tür | Gerekli | Açıklama |
|---|---|---|---|
| stop_id | integer | Evet | load_stops.id for this load |
| event | string | Evet | enter | exit |
| lat | number | Hayır | -90 … 90 |
| lng | number | Hayır | -180 … 180 |
| accuracy | number | Hayır | meters, >= 0 |
| occurred_at | datetime | Hayır | ISO 8601; defaults to now; within last 7 days / +5 minutes |
Aynı yük + stop + event + raporlayan 120 saniye içinde tekrarlanırsa önceki kayıt deduped: true ile döner ve yeni bildirim gönderilmez.
403 - Not assigned driver / not admin. 404 - Load not found or different company. 422 - Validation (e.g. stop_id not on this load).
Nasıl çalışır:
- Load detail → use
stops[].id,lat,lng,type - OS geofence identifier (recommended):
load:{loadId}:stop:{stopId} - On enter/exit callback → call this endpoint (retry / offline queue recommended)
Yük Belgeleri
Yük başına belgeler. Kota = pickup_count + drop_count + 1 ek (pickup/drop durağı başına tek belge slotu). Türler: pickup, drop, additional. Yükleme/değiştirme bağımsız isteğe bağlı parçalar kabul eder: PDF (file veya processed), ham görüntü(ler) ve/veya ocr_text — en az bir parça zorunlu. Belge başına en fazla 10 ham görüntü; sonradan POST .../raws ile eklenebilir. PDF download/preview ile; ham download/raw, preview/raw veya raws/{rawId} ile; OCR metni liste/detay JSON ve GET ocr-text ile sunulur. Dosya başına maks. 10 MB. Multipart form-data. Web panel PDF yükler veya görselleri PDF’e tarar; ham önizleme ve OCR metni varsa gösterir.
Kimler yönetebilir: admin; can_manage_load_documents=true olan viewer; atanan sürücü (yükleme/değiştirme; durum completed ise silme engellenir).
Kimler listeleyebilir/indirebilir: Yükü görüntüleyebilen aynı şirket kullanıcıları (admin/viewer; atanan sürücü).
load_stop_id: pickup/drop için, o türde 2+ durak varsa zorunludur. Tam olarak bir durak varsa, alan atlandığında sunucu otomatik seçer. additional için her zaman atlayın.
raw ve ocr_text için şirketin ocr_enabled lisans bayrağı gerekir. Yalnızca PDF yüklemeleri (file veya processed tek başına) için gerekmez.
Gerektirir Authorization: Bearer <token> ve check.license.api.
Çoklu durak iş akışı
Her pickup/drop durağında tek belge slotu vardır (slot_index 0). Kota = pickup_count + drop_count + 1 ek. legacy: true işaretli slotlar, tek-slot sınırından önce yüklenmiş fazla belgelerdir ve salt okunurdur. Bir türde 2+ durak varsa load_stop_id zorunludur — sunucu tahmin etmez.
- Slotlardaki load_stop_id için GET yük detayı veya GET documents çağırın.
- type=pickup|drop ve eşleşen load_stop_id ile POST upload (o türde 2+ durak varsa load_stop_id zorunlu). İlk partial ham set yüklenebilir (ör. 10’dan 6).
- Kalan her durak için tekrarlayın; isteğe bağlı olarak bir kez type=additional yükleyin (load_stop_id göndermeyin).
- Document id ile replace / download / preview / ocr-text kullanın. Ham sayfalar için: POST .../raws ile ekle, GET .../raws/{rawId}/preview ile önizle, POST .../raws/{rawId} ile tekini değiştir, DELETE .../raws/{rawId} ile sil.
- Belge üzerindeki DELETE satırı ve hem işlenmiş PDF hem tüm ham görüntü dosyalarını siler.
Örnek: 2 pickup + 2 drop için slot listesi
Örnek: her durağa bir belge (ve isteğe bağlı additional)
Örnek: değiştir, indir, önizle, preview/raw, ocr-text, sil
Durağa tek belge (aynı load_stop_id). Yük başına bir additional. Dolu durakta ikinci store 422 döner. Dolu slota yeniden yükleme için store değil, o belgenin id’si ile replace kullanın. Ham sayfalar: belge başına en fazla 10 — eklemek için POST .../raws, tekini değiştirmek için POST .../raws/{rawId}, silmek için DELETE .../raws/{rawId}.
Belgeleri Listele
GET /api/v1/loads/{id}/documents
Liste/detaydaki her belge nesnesi hangi parçaların saklandığını bayraklarla gösterir:
| Alan | Notlar |
|---|---|
| id, load_id, type, load_stop_id | Document identity + slot link |
| has_pdf | true when a processed PDF is stored |
| original_name, size_bytes, mime | PDF metadata when has_pdf=true; otherwise null / display name from raw |
| has_raw | true when at least one raw image is stored |
| raw_size_bytes, raw_mime, raw_original_name | Primary raw (sort_order 0) metadata; null when has_raw=false |
| raw_count, raws[] | Additive: count + list of {id, sort_order, size_bytes, mime, original_name} |
| has_ocr_text | true when non-empty ocr_text is stored |
| ocr_text | Full client-supplied OCR string (or null). Max 500000 chars. One combined string per document. |
Belge Yükle
POST /api/v1/loads/{id}/documents — multipart/form-data
Bağımsız isteğe bağlı parçalar — şu kombinasyonlardan herhangi biri: PDF (file VEYA processed), raw/raw[], ocr_text. En az bir parça zorunlu. file ile processed’ı birlikte göndermeyin. raw ve ocr_text için ocr_enabled gerekir.
| Alan | Notlar |
|---|---|
| file | İsteğe bağlı PDF (maks. 10 MB). processed ile aynı — file VEYA processed gönderin, ikisini birden değil. raw ve/veya ocr_text ile birlikte kullanılabilir. |
| raw | İsteğe bağlı: tek görüntü veya 1..10 elemanlı raw[] (JPEG/PNG/HEIC/HEIF, her biri maks. 10 MB). Tek başına veya PDF/ocr_text ile gönderilebilir. ocr_enabled gerekir. Tekil raw tam desteklenmeye devam eder. |
| processed | İsteğe bağlı PDF (maks. 10 MB). file ile aynı — file VEYA processed gönderin, ikisini birden değil. İndirme/önizleme bunu sunar. raw ve/veya ocr_text ile birlikte kullanılabilir. |
| ocr_text | İsteğe bağlı düz metin (maks. 500000 karakter). Tek başına veya PDF/raw ile gönderilebilir. ocr_enabled gerekir. Değiştirmede alanı göndermezseniz mevcut metin korunur; boş string göndererek temizleyebilirsiniz. |
| type | pickup | drop | additional |
| load_stop_id | nullable integer; pickup/drop için, o türde 2+ durak varsa zorunlu; tam bir tane varsa otomatik; additional için atla |
Yalnızca PDF (file veya processed)
Yalnızca ham görüntü(ler)
Yalnızca OCR metni
Tüm parçalar (ham + işlenmiş PDF + OCR metni)
422 — validasyon / boş yük / file+processed çakışması / kota aşıldı / durağın zaten belgesi var / tür uyuşmazlığı. 403 — belgeleri yönetme yetkiniz yok veya raw/ocr_text gönderirken OCR etkin değil.
Belge Değiştir
POST /api/v1/loads/{id}/documents/{documentId} — multipart/form-data
Aynı belge kimliğini, türünü ve durak bağlantısını korur. Yalnızca gönderdiğiniz parçalar güncellenir; gönderilmeyen PDF, ham ve OCR korunur. file/processed, raw veya ocr_text’ten en az biri zorunlu. ocr_text yalnızca alan gönderildiğinde güncellenir (boş string temizler). raw/raw[] gönderildiğinde tüm ham set değişir (birleştirme değil). Mevcut sayfaları yeniden yüklemeden eklemek için POST .../documents/{id}/raws kullanın.
Bağımsız isteğe bağlı parçalar — şu kombinasyonlardan herhangi biri: PDF (file VEYA processed), raw/raw[], ocr_text. En az bir parça zorunlu. file ile processed’ı birlikte göndermeyin. raw ve ocr_text için ocr_enabled gerekir.
| Alan | Notlar |
|---|---|
| file | İsteğe bağlı PDF (maks. 10 MB). processed ile aynı — file VEYA processed gönderin, ikisini birden değil. raw ve/veya ocr_text ile birlikte kullanılabilir. |
| raw | İsteğe bağlı: tek görüntü veya 1..10 elemanlı raw[] (JPEG/PNG/HEIC/HEIF, her biri maks. 10 MB). Tek başına veya PDF/ocr_text ile gönderilebilir. ocr_enabled gerekir. Tekil raw tam desteklenmeye devam eder. |
| processed | İsteğe bağlı PDF (maks. 10 MB). file ile aynı — file VEYA processed gönderin, ikisini birden değil. İndirme/önizleme bunu sunar. raw ve/veya ocr_text ile birlikte kullanılabilir. |
| ocr_text | İsteğe bağlı düz metin (maks. 500000 karakter). Tek başına veya PDF/raw ile gönderilebilir. ocr_enabled gerekir. Değiştirmede alanı göndermezseniz mevcut metin korunur; boş string göndererek temizleyebilirsiniz. |
Kısmi değiştirme (yalnızca gönderilen parçalar güncellenir; diğerleri korunur)
403 / 404 — yükleme ile aynı erişim kuralları; belge yüke ait olmalıdır; raw veya ocr_text gönderirken OCR lisansı gerekir.
Ham Görüntü Ekle
YENİPOST /api/v1/loads/{id}/documents/{documentId}/raws — multipart/form-data
Mevcut sayfaları silmeden belgeye bir veya daha fazla ham görüntü ekler. raw veya raw[] (JPEG/PNG/HEIC/HEIF, her biri maks. 10 MB). mevcut + yeni ≤ 10 olmalı. ocr_enabled gerekir. Store ile aynı yükleme yetkisi. Güncellenmiş belgeyi döner (raws[], raw_count).
422 / 403 / 404 — mevcut + yeni 10’u aşarsa 422; yetkisiz veya OCR kapalıysa 403; belge yoksa 404.
Tek Ham Görüntüyü Değiştir
YENİPOST /api/v1/loads/{id}/documents/{documentId}/raws/{rawId} — multipart/form-data
Id ile tek bir ham görüntüyü değiştirir. Multipart alanı raw (tek dosya). Aynı raw id ve sort_order korunur; kardeşlere dokunulmaz. ocr_enabled gerekir. Güncellenmiş belgeyi döner.
403 / 404 — append ile aynı erişim kuralları; raw belgeye ait olmalı.
Tek Ham Görüntüyü Sil
YENİDELETE /api/v1/loads/{id}/documents/{documentId}/raws/{rawId}
Id ile tek bir ham görüntüyü siler ve sort_order’ı 0..n-1 olacak şekilde yeniden sıkıştırır. PDF ve ocr_text korunur. Son raw silinince belge PDF/OCR-only kalır (has_raw=false). Güncellenmiş belgeyi döner. Yük tamamlandığında sürücü silemez.
403 / 404 — belge silme ile aynı erişim kuralları; raw belgeye ait olmalı.
Belge Sil
DELETE /api/v1/loads/{id}/documents/{documentId}
403 — yük durumu tamamlandığında sürücü silemez.
Belge İndir
GET /api/v1/loads/{id}/documents/{documentId}/download
İşlenmiş PDF ikilisini (Content-Type: application/pdf) dosya indirme olarak döndürür — JSON zarfı değildir. has_pdf false ise (PDF yok) 404.
404 — belge yok veya PDF saklanmamış (has_pdf=false). 403 — sürücü yalnızca kendine atanmış yükün belgelerine erişebilir.
Ham Görüntüyü İndir
GET /api/v1/loads/{id}/documents/{documentId}/download/raw
Ham çekim görüntüsünü (JPEG/PNG/HEIC) dosya indirme olarak döndürür. Belgede ham dosya yoksa 404. İndirme ile aynı yetki; JSON zarfı değildir.
Content-Type: image/jpeg | image/png | image/heic | image/heif.
404 — bu belge için ham görüntü yok. 403 — sürücü yalnızca kendine atanmış yükün belgelerine erişebilir.
Belge Önizleme
GET /api/v1/loads/{id}/documents/{documentId}/preview
İşlenmiş PDF’yi uygulama içi görüntüleme için stream eder (Content-Disposition: inline). İndirme ile aynı yetki; JSON zarfı değildir. has_pdf false ise 404.
404 — belge yok veya PDF saklanmamış (has_pdf=false). 403 — sürücü yalnızca kendine atanmış yükün belgelerine erişebilir.
Ham Görüntü Önizleme
GET /api/v1/loads/{id}/documents/{documentId}/preview/raw
GET /api/v1/loads/{id}/documents/{documentId}/raws/{rawId}/preview · .../raws/{rawId}/download
Ham çekim görüntüsünü uygulama içi görüntüleme için stream eder (Content-Disposition: inline + raw_mime). Image/WebView önizlemesi için kullanın. Dosyayı kaydetmek için download/raw tercih edin. Belgede ham dosya yoksa 404. İndirme ile aynı yetki; JSON zarfı değildir.
Belirli bir ham görüntüyü id ile stream eder (Content-Disposition: inline veya attachment). raw_count > 1 iken bunu tercih edin. Eski GET .../preview/raw ve .../download/raw birincil hamı (sort_order 0) sunmaya devam eder.
JPEG/PNG çoğu tarayıcıda açılır; HEIC/HEIF için cihazda yerel görüntüleyici gerekebilir.
Content-Type: image/jpeg | image/png | image/heic | image/heif.
404 — bu belge için ham görüntü yok. 403 — sürücü yalnızca kendine atanmış yükün belgelerine erişebilir.
OCR Metnini Al
GET /api/v1/loads/{id}/documents/{documentId}/ocr-text
Tek bir belgenin saklanan OCR metnini JSON zarfı olarak döndürür. Yalnızca metin gerektiğinde tercih edin (tüm belge listesini yeniden çekmez). İndirme ile aynı yetki. OCR yüklenmemişse ocr_text null, has_ocr_text false olur.
Tam ocr_text ayrıca GET documents ve GET yük detayı içinde (documents[].ocr_text) gömülüdür. Bu uç tek belge ekranları içindir.
403 — sürücü yalnızca kendine atanmış yükün belgelerine erişebilir. 404 — belge yok veya PDF saklanmamış (has_pdf=false).
Yük listesi ve yük detayı (GET /loads, GET /loads/{id}) ayrıca içerir documents ve document_quota (Bağımsız isteğe bağlı parçalar — şu kombinasyonlardan herhangi biri: PDF (file VEYA processed), raw/raw[], ocr_text. En az bir parça zorunlu. file ile processed’ı birlikte göndermeyin. raw ve ocr_text için ocr_enabled gerekir.).
Sürücü İstatistikleri
YENİGET /api/v1/drivers/stats — ?driver_id= admin/viewer için zorunlu; sürücü göndermez (yalnızca kendi)
Şirket saat diliminde takvim günü / hafta (Pzt–Paz) / ay toplamları: mesafe (km veya mi), moving_seconds ve stopped_seconds (kısa idle stopped’a dahil). Tamamlanan günler gece pre-aggregation’dan; bugün sıcak location history’den canlı hesaplanır (replay yer değişimi + IFTA segment filtreleri).
403 — sürücü başka driver_id isteyemez; veya paket carrier/broker değil. 404 — sürücü şirkette yok. 422 — admin/viewer için driver_id eksik.
Yük (Paylaşım Tokenı)
GET /api/v1/loads/by-token/{token} - Auth yok
Paylaşım linki ile (/l/{token}) veya deep link ile (traxnavi://load/{token}), açıldığında mobil uygulama bu endpoint ile yükü çeker. Token geçerli ve expires_at dolmamış olmalı.
Yük Push Bildirimleri
Sürücüler, yük yaşam döngüsü olaylarında otomatik FCM push bildirimleri alır. Polling gerekmez; ekranlarınızı aşağıdaki payload'a göre bağlayın.
Ön Koşul: Cihaz, FCM token'ını şu uç ile kaydetmelidir: POST /api/v1/device-tokens (Cihaz Tokenları bölümüne bakın) girişten hemen sonra. Sunucu, kullanıcı başına tek bir aktif cihaz zorunlu kılar; çıkış yapmak, tekrar giriş yapmak veya şifre sıfırlamak, kullanıcının tüm FCM token'larını otomatik olarak kaldırır. DELETE /api/v1/device-tokens/{token} opsiyoneldir; yalnızca uygulama oturumu kapatmadan push almayı durdurmak istediğinde kullanılır.
Olaylar
| Olay Tipi | Alıcı | Tetikleyici |
|---|---|---|
load_created |
Yöneticiler/izleyiciler (işlemi yapan hariç) | Web panelinde bir yük oluşturulur |
load_assigned |
Atanan sürücü | Admin web üzerinden sürücü atar (yük oluştur/düzenle) |
load_status_updated |
Atanan sürücü + admin/viewer'lar | Herhangi bir uçta (web veya API) durum değişir. Değişikliği tetikleyen kullanıcı hariç tutulur. |
load_deleted |
Atanan sürücü ve yöneticiler/izleyiciler (işlemi yapan hariç) | Web panelinde bir yük silinir |
geofence_entered / geofence_exited |
Yöneticiler/izleyiciler (işlemi yapan hariç) | Mobil uygulama POST /loads/{id}/geofence-events ile enter/exit bildirir |
new_message |
Sohbet katılımcıları (gönderen hariç) | Bir sohbete mesaj gönderilir |
load_created
Web'de bir yük oluşturulduğunda yöneticilere/izleyicilere (oluşturan hariç) gönderilir. Varsayılan Android kanalını kullanır. Başlık/gövde alıcının yerel ayarına göre yerelleştirilir. default.
load_assigned
Admin web panelden bir sürücü atadığında gönderilir (yük oluştur veya düzenle). Android şu kanalı kullanır: loads kanalı; iOS standart alert payload'ı kullanır: badge: 1, mutable-content: 1 ve content-available: 1.
load_status_updated
Durum; sürücünün kendisi dışındaki biri tarafından web veya API üzerinden değiştirildiğinde atanan sürücüye, her durum değişikliğinde de admin/viewer'lara (değişikliği yapan hariç) gönderilir. Genel sistem kanalını kullanır; payload tipi: load_status_updated. Başlık/gövde alıcının diline göre yerelleştirilir.
geofence_entered / geofence_exited
Mobil uygulama geofence enter/exit bildirdiğinde şirket admin/viewer kullanıcılarına (raporlayan hariç) gönderilir. Default kanalı kullanır. Ayrıca uygulama içi bildirim kaydı oluşur; e-posta yalnızca alıcının mail bildirimi açıksa gider.
load_deleted
Web'de bir yük silindiğinde gönderilir. Atanan sürücü, loads kanalında load_id alanlı bir payload alır; uygulama yükü listelerden kaldırabilir. Diğer yöneticiler/izleyiciler genel default push alır (type/title/body).
Mobil Entegrasyon Rehberi
Gerekli Android Kanalları
Push ses/öncelik davranışının doğru çalışması için bu bildirim kanallarını uygulama açılışında bir kez oluşturun:
| Kanal ID | Kullanım Amacı | Önem |
|---|---|---|
loads |
load_assigned, load_deleted |
HIGH |
messages |
new_message |
HIGH |
default |
load_status_updated, geofence_entered, geofence_exited, sistem uyarıları |
HIGH |
Not: Düzenleme ile bir sürücüden diğerine yeniden atama yapılırsa yalnızca yeni sürücü şunu alır: load_assigned. Geçersiz, kayıtsız veya bilinmeyen tokenlar ilk başarısız gönderimden sonra veritabanından otomatik silinir.
Uygulama İçi Bildirim Kaydı
Push'a ek olarak her load_assigned / load_status_updated / load_deleted / geofence_entered / geofence_exited olayı ayrıca şu tabloda saklanır: notifications alıcı için (sürücüler dahil). Böylece gelecekteki uygulama sürümleri, ayrı bir uç değişikliğine gerek kalmadan zil simgesi geçmişini gösterebilir.