Navvo
مرجع الواجهة البرمجية

WebSocket الملاحة

أرسل مواقع GPS واستقبل التقدم والمسارات الجديدة والبدائل وتنبيهات المخاطر عبر اتصال مباشر واحد.

WebSocket الملاحة

بدلًا من إرسال PATCH كل ثانية أو ثانيتين، أبقِ اتصال WebSocket واحدًا مفتوحًا لكل جلسة ملاحة. تُرسَل عبره المواقع، وتصل عبره بيانات التقدم والمسارات الجديدة والمسارات البديلة وتنبيهات المخاطر.

أنشئ الجلسة أولًا عبر POST /navigation/sessions. ويبقى إنهاؤها عبر REST أيضًا. واحتفظ بـ PATCH /navigation/sessions/{id} خيارًا احتياطيًا عند انقطاع الاتصال.

الاتصال

wss://navvo.io/api/v1/navigation/sessions/{sessionId}/live

صادِق أثناء المصافحة ببيانات الاعتماد نفسها التي تستخدمها مع REST.

الطريقةالكيفية
مستخدم مسجّل الدخولالترويسة Authorization: Bearer <JWT>
مفتاح APIالترويسة X-Api-Key: <key>
تطبيق لا يستطيع ضبط الترويساتمعامل الاستعلام ?token=<JWT>

استخدم الترويسة كلما أمكن، لأن الرمز الموجود في عنوان URL قد يصل إلى السجلات.

أرسل ping كل 25 ثانية. وإذا لم يصل pong خلال 10 ثوانٍ، فأغلق الاتصال وأعد الاتصال. ويقطع الخادم الاتصال الصامت لمدة 90 ثانية.

لكل جلسة اتصال واحد في الوقت نفسه، ويحلّ الاتصال الجديد محل السابق.

صيغة الرسائل

كل رسالة إطار نصي بصيغة JSON وترميز UTF-8.

{ "type": "<string>", "timestamp": "2026-11-10T11:05:00.123Z", "payload": { } }

الحدود: 16 كيلوبايت لكل رسالة و20 رسالة في الثانية. وتُهمل الإطارات التي تتجاوز المعدل.

الرسائل التي ترسلها

location_update

أرسل رسالة لكل موقع GPS صالح، بمعدل مرة إلى مرتين في الثانية.

{
  "type": "location_update",
  "timestamp": "2026-11-10T11:05:01.450Z",
  "payload": {
    "lat": 31.953949,
    "lng": 35.910635,
    "bearing": 215.4,
    "speed": 18.2,
    "routeRevision": 2,
    "capturedAt": "2026-11-10T11:05:01.400Z"
  }
}
lat, lng
number required
الموقع.
bearing
number
اتجاه GPS بالدرجات باتجاه عقارب الساعة من الشمال. لا ترسل قراءة البوصلة أبدًا. ولا يُستخدم إلا مع speed لا تقل عن 2 متر في الثانية.
speed
number
بالمتر في الثانية.
routeRevision
integer
مراجعة المسار الذي تتبعه. أرسلها دائمًا.
capturedAt
string
وقت التقاط موقع GPS بصيغة ISO 8601. أرسله دائمًا.

تُتجاهل قيمة bearing أو speed غير الصالحة ويُحتسب الموقع رغم ذلك. وأثناء انشغال الخادم يُحتفظ بأحدث موقع فقط.

request_reroute

اطلب مسارًا جديدًا من موقع المركبة، مثلًا من زر إعادة التوجيه. لا يحتاج اكتشاف الخروج عن المسار إلى هذه الرسالة، لأن الخادم يستنتجه من مواقعك. ويمكنك إرسال طلب واحد كل 5 ثوانٍ.

{
  "type": "request_reroute",
  "timestamp": "2026-11-10T11:05:03.000Z",
  "payload": {
    "reason": "manual",
    "currentLocation": { "lat": 31.9542, "lng": 35.9101 },
    "routeRevision": 2
  }
}

select_alternative

انتقل إلى مسار عرضته الرسالة alternative_available.

{
  "type": "select_alternative",
  "timestamp": "2026-11-10T11:05:10.000Z",
  "payload": { "alternativeId": "alt_3fa91c0b27de", "routeRevision": 2 }
}

الرسائل التي تستقبلها

progress

رسالة لكل موقع يعالجه الخادم.

{
  "type": "progress",
  "timestamp": "2026-11-10T11:05:01.490Z",
  "payload": {
    "routeRevision": 2,
    "staleFix": false,
    "offRoute": false,
    "wrongWay": false,
    "arrived": false,
    "shapeIndex": 184,
    "snapped": { "lat": 31.95394, "lng": 35.91062 },
    "distanceToRouteMeters": 2,
    "distanceRemainingMeters": 8450,
    "durationRemainingSeconds": 580,
    "distanceToNextManeuverMeters": 350,
    "progressFraction": 0.15,
    "nextManeuver": {
      "instruction": "Keep left toward Zahran St",
      "verbalAlert": "In 350 meters, keep left toward Zahran Street",
      "type": "fork",
      "modifier": "left",
      "maneuverCode": 24
    }
  }
}

عندما تكون staleFix بقيمة true تجاهل قيم التقدم في هذه الرسالة. وقد تكون nextManeuver بقيمة null.

تكون type إحدى القيم depart وarrive وcontinue وturn وuturn وramp وexit وfork وmerge وroundabout وferry. وتكون modifier إحدى القيم left وright وslight_left وslight_right وsharp_left وsharp_right وstraight وenter وexit أو null.

route_updated

تغيّر المسار. استبدل المسار المعروض واحفظ قيمة routeRevision الجديدة. وتجاهل أي رسالة بمراجعة أقل مما لديك.

{
  "type": "route_updated",
  "timestamp": "2026-11-10T11:05:04.120Z",
  "payload": {
    "routeRevision": 3,
    "reason": "off_route_auto_recovery",
    "totalDistanceMeters": 8920,
    "totalDurationSeconds": 610,
    "routeGeometry": [[31.9542, 35.9101], [31.95435, 35.91001]],
    "routeShapeEncoded": "…",
    "maneuvers": [],
    "trafficSegments": []
  }
}
reasonالمعنى
off_route_auto_recoveryخرجت المركبة عن المسار
wrong_way_auto_recoveryسارت المركبة عكس المسار لمدة 3 ثوانٍ
reroute_requestedرد على request_reroute أو إعادة حساب عبر REST
alternative_selectedرد على select_alternative
resyncكانت routeRevision لديك متأخرة، مثلًا بعد إعادة الاتصال

تتكون routeGeometry من أزواج [lat, lng]، وrouteShapeEncoded هو الخط نفسه بصيغة polyline6. وفي maneuvers تكون type هي القيمة النصية أعلاه وmaneuverCode هو الرمز الرقمي. أما trafficSegments فتكون فارغة دائمًا حاليًا.

alternative_available

طريق آخر للوصول إلى الوجهة. يتحقق الخادم مرة كل دقيقة تقريبًا ويعرض المسارات التي لا تزيد مدتها على 5 دقائق.

{
  "type": "alternative_available",
  "timestamp": "2026-11-10T11:06:00.000Z",
  "payload": {
    "alternativeId": "alt_3fa91c0b27de",
    "routeRevision": 3,
    "name": "Via Zahran St",
    "summary": "Save 4 min",
    "durationDifferenceSeconds": -240,
    "distanceDifferenceMeters": 350,
    "forkPoint": { "lat": 31.9551, "lng": 35.9082 },
    "routeGeometry": [[31.9551, 35.9082]],
    "routeShapeEncoded": "…",
    "expiresAt": "2026-11-10T11:08:00.000Z"
  }
}

توقف عن عرض البديل عند expiresAt أو عند وصول route_updated. والقيمة نفسها في alternativeId تعني البديل نفسه.

hazard_alert

تُرسل مرة واحدة لكل خطر عندما يصبح ضمن 600 متر أمامك على المسار.

{
  "type": "hazard_alert",
  "timestamp": "2026-11-10T11:06:30.000Z",
  "payload": {
    "alertId": "inc_77492",
    "category": "speed_camera",
    "severity": "medium",
    "distanceMeters": 600,
    "location": { "lat": 31.9582, "lng": 35.9015 },
    "voiceAlert": "Speed camera reported ahead in 600 meters",
    "speedLimitKmh": 80
  }
}

تكون category إما speed_camera أو نوع حادث مثل accident أو closure أو construction أو jam. ولا تظهر speedLimitKmh إلا عند معرفة الحد.

error

تعذّر استخدام الرسالة. يبقى الاتصال مفتوحًا.

{ "type": "error", "timestamp": "…", "payload": { "code": "INVALID_MESSAGE", "detail": "…" } }

الرموز: INVALID_JSON وINVALID_MESSAGE وUNKNOWN_TYPE وALTERNATIVE_UNAVAILABLE وRATE_LIMITED وINTERNAL.

مراجعات المسار

تُبقي routeRevision تطبيقك والخادم متوافقين، سواء عبر WebSocket أو عبر PATCH.

  1. احفظ أعلى مراجعة طبّقتها.
  2. أرسلها مع كل موقع.
  3. بعد أي انقطاع، أرسل موقعًا مع المراجعة المحفوظة. وإذا كنت متأخرًا فستصلك route_updated بالسبب resync.

انقطاع الاتصال

رمز الإغلاقالمعنىما يجب فعله
1000انتهت الرحلةتوقف
4001الجلسة غير موجودة أو منتهيةتوقف. وابدأ جلسة جديدة إذا كانت الملاحة مستمرة
4003بيانات اعتماد مفقودة أو غير صالحةتوقف. جدّد تسجيل الدخول ثم أعد الاتصال مرة واحدة
4009حلّ محله اتصال أحدثتوقف
1011مشكلة مؤقتة في الخادمأعد الاتصال
1012الخدمة تعيد التشغيلأعد الاتصال
1013الخدمة متوقفة مؤقتًاأعد الاتصال واستخدم PATCH في هذه الأثناء
أي رمز آخرفقدان الشبكة أو إعادة تشغيل الخادمأعد الاتصال

قد تفشل المصافحة أيضًا برمز HTTP 503 أثناء توقف الخدمة. وتعامل معه مثل 1013.

لإعادة الاتصال، أعد المحاولة بعد ثانية ثم ثانيتين ثم 4 ثوانٍ، ثم كل 4 ثوانٍ. وبعد انقطاع يتجاوز 5 ثوانٍ، أرسل PATCH /navigation/sessions/{id} مع routeRevision وcapturedAt. وعند عودة الاتصال أوقف PATCH وأرسل location_update فورًا.

إنهاء الرحلة

POST /api/v1/navigation/sessions/{id}/complete
{ "rating": "up", "message": "Great route", "distanceKm": 12.4, "durationSec": 900 }

جميع الحقول اختيارية. تنتهي الرحلة ويُغلق الاتصال بالرمز 1000. ولإلغاء رحلة استخدم DELETE /navigation/sessions/{id}.

Copyright © 2026