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

الملاحة

مستوى التحكّم في الملاحة اللحظية منعطفاً بمنعطف — جلسات مُدارة، وتقدّم وخروج عن المسار محسوبان من الخادم، وزمن وصول متوقّع حيّ، واكتشاف الوصول، وسجل أحداث، ونص إرشاد منطوق.

الملاحة

مستوى تحكّم في الملاحة مدرك للخادم لبناء تجربة توجيه منعطفاً بمنعطف بمستوى خرائط Google دون إعادة اختراع الهندسة الصعبة على العميل. يعتمد على التوجيه وحركة المرور: تبدأ جلسة لرحلة، وتغذّيها بقراءات GPS حيّة، فيحسب الخادم التقدّم بمحاذاة المسار، واكتشاف الخروج عن المسار، وإعادة التوجيه التلقائية، وزمن وصول متوقّع مراعٍ لحركة المرور، واكتشاف الوصول، وسجل أحداث متجدّد (مع خطافات ويب موقَّعة اختيارية).

كما يتوفّر كل مساعد عديم الحالة (off-route، progress، arrival-check) بمفرده إن كنت تفضّل إدارة الحلقة من جهة العميل.

النطاق المطلوب: routing

المصادقة. الملاحة خدمة للأعضاء: كل نقطة نهاية تتطلب مستدعياً معرَّفاً — رمز Bearer لمستخدم Navvo مسجَّل أو مفتاح API الخاص بك (x-api-key). الطلبات المجهولة تعيد 401. الجلسات مملوكة لمن أنشأها؛ ومحاولة مستدعٍ آخر قراءة جلستك أو تحديثها تعيد 403.
الإحداثيات هي { lat, lng } في كل جسم من أجسام الملاحة (بخلاف تمرير التوجيه منخفض المستوى الذي يستخدم lon). هندسة المسار (routeShape) هي خط مُرمَّز بدقّة 6 (المعروف بـ polyline6) — فُكّه بمعامل 1e6. تُعيد كل طلبات POST 201 عند النجاح.

POST /navigation/sessions

ابدأ جلسة ملاحة مُدارة. يخطّط الخادم المسار (عبر محرّك التوجيه لدى Navvo)، ويحلّل المنعطفات مع المسافات التراكمية، ويعيد جلسة يمكنك إدارتها عبر PATCH/positions.

جسم الطلب

origin
object required
نقطة البداية { "lat": number, "lng": number }.
destination
object required
نقطة النهاية { "lat": number, "lng": number, "name"?: string, "placeSlug"?: string }. يتيح placeSlug لاكتشاف الوصول تحديد مدخل مُخرَّط.
costing
string
وسيلة التنقّل: auto (الافتراضي)، pedestrian، bicycle، motor_scooter، truck، wheelchair.
language
string
لغة الإرشاد/الصوت (مثل en-US، ar). الافتراضي en-US.
preference
string
fastest أو shortest أو balanced.
avoid
string[]
أيٌّ من tolls، highways، ferries، unpaved.
webhookUrl
string
عنوان https اختياري لاستقبال أحداث الملاحة. التسليمات موقَّعة بـ HMAC (انظر خطافات الويب).
curl -s -X POST "https://navvo.io/api/v1/navigation/sessions" \
  -H "Authorization: Bearer $NAVVO_JWT" -H "Content-Type: application/json" \
  -d '{
        "origin": { "lat": 31.9539, "lng": 35.9106 },
        "destination": { "lat": 31.9730, "lng": 35.9200, "name": "Sports City" },
        "costing": "auto", "language": "en-US"
      }'

الاستجابة (201)

{
  "sessionId": "b23f9bec-516c-4038-a2fa-c3a275ec598b",
  "status": "active",
  "costing": "auto",
  "language": "en-US",
  "destination": { "lat": 31.9730, "lng": 35.9200, "name": "Sports City" },
  "routeShape": "…encoded polyline6…",
  "maneuvers": [
    {
      "index": 0, "type": 1, "instruction": "Drive north.",
      "verbalAlert": "Drive north.", "verbalPre": "Drive north for 300 meters.",
      "verbalPost": "Continue for 300 meters.", "streetNames": ["King Abdullah St"],
      "roundaboutExit": null, "exitSign": null,
      "distanceMeters": 300, "timeSeconds": 34,
      "lat": 31.9539, "lng": 35.9106, "cumulativeMeters": 0
    }
  ],
  "distanceMeters": 6366,
  "baseSeconds": 402,
  "etaSeconds": 402,
  "distanceRemainingMeters": 6366,
  "durationRemainingSeconds": 402,
  "maneuverIndex": 0,
  "eventSeq": 0,
  "expiresAt": "2026-07-20T02:00:00.000Z",
  "route": { "shape": "…", "maneuvers": [ … ], "distanceMeters": 6366, "etaSeconds": 402 }
}
الحقلالمعنى
maneuvers[]قائمة المنعطفات المحلّلة. type رمز منعطف — حلّه عبر GET /routing/maneuver-types. وcumulativeMeters هي المسافة من بداية المسار حتى ذلك المنعطف (تُستخدم للتقدّم). وحقول verbal* جاهزة للتحويل إلى كلام.
distanceMeters / baseSecondsإجمالي طول المسار ومدّته دون حركة مرور.
eventSeqعدّاد أحداث تصاعدي — استطلِع GET …/events?since= بآخر قيمة رأيتها.
expiresAtتنتهي صلاحية الجلسات تلقائياً بعد ~6 ساعات من آخر نشاط.

الأخطاء: 400 إذا تعذّر تخطيط مسار بين النقطتين (أو costing: "truck" حيث توجيه الشاحنات غير مُهيّأ)؛ و401 عند عدم المصادقة.


GET /navigation/sessions/{id}

اجلب لقطة الجلسة الحالية (المسار، المنعطفات، التقدّم، status). تُعيد 404 إن كانت غير معروفة، و403 إن كانت مملوكة لمستدعٍ آخر.


PATCH /navigation/sessions/{id}

غذِّ أحدث قراءة GPS. يحاذيها الخادم مع المسار، ويقدّم مؤشّر المنعطف، ويكتشف الوصول والخروج عن المسار (مع إعادة تخطيط تلقائية عند الخروج)، ويُلحق أي أحداث، ويعيد progress المحدَّث.

جسم الطلب

lat
number required
خط العرض الحالي.
lng
number required
خط الطول الحالي.
speed
number
السرعة الأرضية بالمتر/الثانية (تضبط نافذة «الاقتراب من المنعطف»).
heading
number
الاتجاه فوق الأرض بالدرجات.
capturedAt
string
الطابع الزمني ISO للقراءة.

الاستجابة (201)

{
  "sessionId": "…", "status": "active", "maneuverIndex": 2, "eventSeq": 4,
  "etaSeconds": 237, "distanceRemainingMeters": 3756, "durationRemainingSeconds": 237,
  "progress": {
    "offRoute": false,
    "arrived": false,
    "shapeIndex": 128,
    "maneuverIndex": 2,
    "snapped": { "lat": 31.9601, "lng": 35.9149 },
    "distanceToRouteMeters": 6,
    "distanceRemainingMeters": 3756,
    "durationRemainingSeconds": 237,
    "distanceToNextManeuverMeters": 210,
    "nextManeuver": { "index": 2, "type": 15, "instruction": "Turn left onto …", "verbalAlert": "Turn left onto …", "cumulativeMeters": 3966, "lat": 31.96, "lng": 35.915 },
    "progressFraction": 0.41
  },
  "reroute": null
}

عندما تقع القراءة خارج ممرّ المسار، تصبح progress.offRoute بقيمة true، ويُطلَق حدث off_route، ويعيد الخادم التخطيط من الموضع الحالي: عندئذٍ تحمل reroute القيم الجديدة { shape, maneuvers, distanceMeters, etaSeconds } ويُسجَّل حدث rerouted. وعند بلوغ ~35م من الوجهة تتحوّل الجلسة إلى status: "arrived" ويُطلَق حدث arrived.


DELETE /navigation/sessions/{id}

أنهِ الجلسة (status: "cancelled"). تُعيد { "ended": true, "sessionId": "…", "status": "cancelled" }.


POST /navigation/sessions/{id}/positions

أرسِل دفعة من القراءات الحديثة (حتى 50) — مفيدة لوصلة صاعدة تعمل في الخلفية/بدورة تشغيل. تقود أحدث قراءة تحديثَ التقدّم المرجعي؛ وتماثل الاستجابة PATCH إضافةً إلى accepted (العدد) وnewEvents (الأحداث الناتجة عن هذه الدفعة).

{ "positions": [ { "lat": 31.958, "lng": 35.897, "speed": 11 }, { "lat": 31.960, "lng": 35.915, "speed": 9 } ] }

GET /navigation/sessions/{id}/events

استطلِع سجل أحداث الجلسة. مرّر ?since=<eventSeq> للحصول على الأحداث الأحدث فقط.

{
  "sessionId": "…", "status": "active", "eventSeq": 6,
  "events": [
    { "seq": 4, "type": "maneuver_completed", "at": "2026-07-19T18:02:11.000Z", "data": { "maneuverIndex": 1, "instruction": "…" } },
    { "seq": 5, "type": "off_route", "at": "…", "data": { "distanceToRouteMeters": 67 } },
    { "seq": 6, "type": "rerouted", "at": "…", "data": { "reroutes": 1, "distanceMeters": 4175 } }
  ]
}

أنواع الأحداث: maneuver_approaching، maneuver_completed، off_route، rerouted، arrived. يُحتفَظ بآخر ~50 حدثاً لكل جلسة.


GET /navigation/sessions/{id}/eta

أعِد حساب زمن الوصول المتوقّع المراعي لحركة المرور للمسار المتبقّي (من آخر موضع مُحاذى فصاعداً). هذا هو البديل الزهيد المقيَّد بالجلسة عن استطلاع POST /traffic/route بشكل مبنيّ يدوياً.

{
  "sessionId": "…", "available": true, "etaSeconds": 660,
  "arrivalTime": "2026-07-19T18:15:00.000Z",
  "delaySeconds": 120, "trafficLevel": "slow", "source": "traffic"
}

عندما تكون حركة المرور الحية غير متاحة تُعيد { "available": false, "etaSeconds": <base>, "source": "base" }.


POST /navigation/off-route

عديم الحالة. اختبر موضعاً واحداً مقابل ممرّ مسار — دون حاجة إلى جلسة.

جسم الطلب

routeShape
string required
هندسة المسار النشط كسلسلة polyline6 مُرمَّزة.
position
object required
{ "lat": number, "lng": number }.
heading
number
الاتجاه فوق الأرض اختياري.
thresholdMeters
number
نصف عرض الممرّ لقرار الخروج عن المسار (5–500، الافتراضي 40).

الاستجابة (201)

{
  "provider": "navvo-navigation",
  "offRoute": true,
  "distanceToRouteMeters": 67.2,
  "confidence": 0.91,
  "snapped": { "lat": 31.9598, "lng": 35.9141 },
  "shapeIndex": 128,
  "alongMeters": 2606
}

snapped هي أقرب نقطة على المسار؛ وalongMeters هي مدى تقدّم تلك النقطة المُحاذاة على طول المسار. وتُعيد 400 إذا لم يفكّ routeShape إلى نقطتين على الأقل.


POST /navigation/recalculate

أعِد تخطيط المسار المتبقّي من الموضع الحالي. يحافظ على تفضيلات الرحلة. إذا مُرِّر sessionId يُستبدَل مسار الجلسة في مكانه (ويُزاد reroutes)؛ وإلا فهي عملية مفردة عديمة الحالة (زوّد destination).

جسم الطلب

sessionId
string
جلسة قائمة لتحديثها. عند وجودها تأخذ destination/costing/preference قيمها الافتراضية من الجلسة.
current
object required
{ "lat": number, "lng": number } — نقطة البداية الجديدة.
destination
object
مطلوبة عند حذف sessionId.
costing
string
تجاوز وسيلة التنقّل.
preference
string
fastest / shortest / balanced.

الاستجابة (201)

{
  "provider": "navvo-navigation",
  "sessionId": "…or null",
  "costing": "auto", "preference": "balanced",
  "route": { "shape": "…encoded polyline6…", "maneuvers": [ … ], "distanceMeters": 4175, "etaSeconds": 260 }
}

POST /navigation/progress

عديم الحالة. أسقِط موضعاً على مسار معروف واحصل على المسافة/الزمن المتبقّيين، وفهرس المنعطف التالي، والوصول — نفس الحسابات التي يجريها PATCH للجلسة، دون جلسة.

جسم الطلب

routeShape
string required
هندسة مسار بصيغة polyline6 مُرمَّزة.
position
object required
{ "lat": number, "lng": number }.
maneuvers
object[]
مراسي منعطفات اختيارية [{ "cumulativeMeters": number }, …] (من جلسة أو /routing/plan) كي تتمكّن الاستجابة من تقديم maneuverIndex.
totalDistanceMeters
number
إجمالي طول المسار؛ يأخذ افتراضياً طول الشكل المفكوك.
baseSeconds
number
مدّة المسار دون حركة مرور؛ تُفعّل durationRemainingSeconds.
arrivalRadiusMeters
number
نصف قطر الوصول (5–200، الافتراضي 30).

الاستجابة (201)

{
  "provider": "navvo-navigation",
  "shapeIndex": 128, "maneuverIndex": 3,
  "snapped": { "lat": 31.9598, "lng": 35.9141 },
  "distanceToRouteMeters": 4.2,
  "distanceRemainingMeters": 2100,
  "durationRemainingSeconds": 280,
  "distanceToNextManeuverMeters": 120,
  "progressFraction": 0.64,
  "arrived": false
}

POST /navigation/arrival-check

عديم الحالة. أكّد الوصول إلى وجهة (وحدِّد أقرب مدخل مُخرَّط عند تزويد placeSlug).

جسم الطلب

destination
object required
{ "lat": number, "lng": number, "placeSlug"?: string }.
position
object required
{ "lat": number, "lng": number } الحالي.
placeSlug
string
يتجاوز destination.placeSlug للبحث عن المدخل.
radiusMeters
number
نصف قطر الوصول (5–200، الافتراضي 30).

الاستجابة (201)

{ "provider": "navvo-navigation", "arrived": true, "distanceMeters": 12.4, "radiusMeters": 30, "entranceId": "ent_3" }

entranceId تكون null عندما لا يملك المكان مداخل مُخرَّطة (أو لم يُزوَّد أيّ منها).


POST /navigation/speak

حوِّل تعليمة منعطف إلى مُخرَج جاهز للنطق. تُعيد دائماً text المُطبَّع، وسلسلة ssml جاهزة للاستخدام (باللغة الصحيحة + معدّل نطق هادئ)، وlanguage المحلولة. وعند تهيئة مزوّد تحويل نص إلى كلام من جهة الخادم تُعيد أيضاً audioUrl؛ وإلا تكون available بقيمة false ويُركّب العملاء الصوت على الجهاز من text/ssml (المسار الافتراضي المُوصى به — نطق عربي/إنجليزي متّسق بزمن استجابة إضافي معدوم).

جسم الطلب

text
string required
التعليمة المراد نطقها (≤ 600 حرف).
language
string
وسم شبيه بـ BCP-47 مثل en-US أو ar-SA. الافتراضي en-US.

الاستجابة (201)

{
  "provider": "navvo-navigation",
  "available": false,
  "reason": "on_device",
  "language": "en-US",
  "text": "In 200 meters, turn right onto King Abdullah Street.",
  "ssml": "<speak xml:lang=\"en-US\"><prosody rate=\"0.94\">In 200 meters, turn right onto King Abdullah Street.</prosody></speak>",
  "audioUrl": null
}

خطافات أحداث الملاحة

إذا أُنشئت جلسة بـ webhookUrl، تُرسَل كل دفعة أحداث جديدة إليه عبر POST بالشكل { "sessionId": "…", "events": [ … ] }. تحمل التسليمات:

  • X-Navvo-Signature: sha256=<hex> — توقيع HMAC-SHA256 لجسم الطلب الخام. تحقّق منه بسرّ الخطاف الخاص بك قبل الوثوق بأي تسليم.
  • X-Navvo-Delivery — رمز قصير لمنع تكرار التسليم (idempotency).

يجب أن يكون العنوان https وأن يُحَلّ إلى عنوان عام — تُرفَض التسليمات إلى نطاقات الاسترجاع/الخاصة (حماية من SSRF). التسليم بأفضل جهد (مهلة 5 ثوانٍ، دون إعادة محاولة)؛ استطلِع GET …/events بوصفه مصدر الحقيقة.


ذات صلة

  • جدول رموز المنعطفات: GET /routing/maneuver-types.
  • ضمّن المسارب وحدود السرعة مباشرةً في الخطة: POST /routing/plan مع includeLanes / includeAttributes.
  • زمن وصول متوقّع مراعٍ لحركة المرور لأي شكل: POST /traffic/route.
  • ساهم بمسارات GPS مجهولة لتحسين حركة المرور الحية (بعد الإرشاد لا أثناءه): POST /telemetry/trips.
Copyright © 2026