Navvo
API Reference

Places

Place listings and rich place detail — categories, hours, photos, ratings, and arrival guidance.

Places

List places and fetch rich detail for a single place, including reviews, photos, Q&A, and arrival intelligence (the recommended entrance and last-50-meters guidance).

Scope required: places

Geometry format. A place's center and each entrance's location are WKT strings, POINT(<lng> <lat>)longitude first. Inside arrivalIntelligence, parsed coordinates are returned as { "lng": …, "lat": … } objects. The rating field on a place object is a string (e.g. "4.60"); on /places/thumb it is a number.

GET /places

List places, paginated, sponsored-first.

curl -s "https://navvo.io/api/v1/places?q=cafe&page=1&limit=20" \
  -H "x-api-key: nvvo_YOUR_KEY"

Query parameters

q
string
Case-insensitive substring match against nameEn or nameAr.
page
number
1-based page number. Defaults to 1 (minimum 1).
limit
number
Page size. Defaults to 50, maximum 100.
sponsored
boolean
Filter to sponsored (or non-sponsored) places.
category
string
Filter to a single category slug — matches a place's canonicalCategorySlugor any entry in its categories array. Discover slugs via GET /places/categories. When set, total reflects the filtered set and the response echoes category.
amenities
string
Comma-separated amenity facet slugs (e.g. wheelchair-accessible-entrance,free-parking-lot). A place matches only if all requested amenities are present and enabled. A slug may be an option (wi-fi) or a whole group (parking = has any parking). When set, total reflects the filtered set and the response echoes the normalized amenities array. Discover available slugs via GET /places/facets.
openNow
boolean
When true, return only places that are currently open (or closing soon), evaluated by the opening-hours engine in Jordan time. Places with no hours data are excluded. total reflects the filtered set and the response echoes openNow: true. Combine with amenities (e.g. "open cafés with parking right now").
sort
string
Result ordering: relevance (default — sponsored, then rating, then newest), rating (highest-rated first), name (A→Z), newest, or oldest. The response echoes the resolved sort.
minRating
number
Only places with a rating this value (05). total reflects the filtered set and the response echoes minRating. Combine with the other filters — e.g. ?minRating=4.5&openNow=true&sort=rating.
near
string
"Near me" — a lat,lng origin (e.g. 31.9539,35.9106). Each result is annotated with distanceKm and the list is sorted nearest-first (this overrides sort). Combine with radiusKm and any filter.
radiusKm
number
With near, return only places within this many kilometres. The response echoes near and radiusKm.

Response

{
  "items": [
    {
      "id": "31c5a4e2-9b1f-4c0a-bb10-2f0c2b8e7a11",
      "slug": "jordan-beans-cafe",
      "nameEn": "Jordan Beans Cafe",
      "nameAr": "مقهى جوردن بينز",
      "logoUrl": "https://navvo.io/uploads/abc123.webp",
      "categories": ["cafe", "food"],
      "canonicalCategorySlug": "cafe",
      "center": "POINT(35.913 31.953)",
      "contact": { "phone": "+962790000000", "website": "https://example.com" },
      "openingHours": { "weekly": { "sunday": "08:00-23:00" } },
      "sponsored": true,
      "claimStatus": "verified",
      "rating": "4.60",
      "entrances": [
        { "id": "a1b2c3d4-…", "type": "main", "label": "Main Entrance", "location": "POINT(35.9131 31.9529)" }
      ]
    }
  ],
  "total": 137,
  "page": 1,
  "limit": 50
}

List items include the entrances relation but not reviews/photos/questions. Ordering is always sponsored DESC, rating DESC, createdAt DESC.


GET /places/thumb

Lightweight thumbnail + open/closed status for a place — ideal for map cards.

curl -s "https://navvo.io/api/v1/places/thumb?slug=jordan-beans-cafe" \
  -H "x-api-key: nvvo_YOUR_KEY"

Query parameters

slug
string required
Place slug.

Response

{
  "url": "https://navvo.io/uploads/abc123.webp",
  "source": "logo",
  "rating": 4.6,
  "openState": "open",
  "openText": "Open · until 23:00"
}
FieldTypeDescription
urlstring | nullBest image — the logo, else a featured photo, else null.
sourcestring | null"logo", "photo", or null.
ratingnumber | nullRating if > 0, else null.
openStatestring | null"open", "closing", "closed", or null (computed in Asia/Amman time).
openTextstring | nullHuman-readable status.

An unknown slug returns 200 with all fields null (not a 404).


GET /places/facets

The available amenity facets across places — grouped (Accessibility, Parking, Payments, Amenities, Service options, …) with per-option counts. Use it to build a "filter by amenity" UI, then pass the chosen slugs to GET /places?amenities=. Only enabled options are counted.

QueryTypeNotes
qstringoptional — narrow the facet counts to places whose name matches
curl -s "https://navvo.io/api/v1/places/facets" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "scanned": 735,
  "capped": false,
  "groups": [
    { "id": "accessibility", "name": "Accessibility", "total": 201, "options": [
      { "slug": "wheelchair-accessible-entrance", "label": "Wheelchair-accessible entrance", "count": 72 },
      { "slug": "wheelchair-accessible-car-park", "label": "Wheelchair-accessible car park", "count": 63 }
    ]},
    { "id": "parking", "name": "Parking", "total": 90, "options": [
      { "slug": "free-parking-lot", "label": "Free parking lot", "count": 27 }
    ]}
  ]
}
FieldTypeNotes
scannednumberplaces examined
cappedbooleantrue if the scan hit its cap (more places exist than were aggregated)
groups[].id / namestringfacet group (e.g. accessibility)
groups[].totalnumbertotal enabled options counted in the group
groups[].options[]array{ slug, label, count }, sorted by count — the slug is what you pass to ?amenities=

GET /places/categories

The full category taxonomy — a hierarchical tree (parent → children) with each category's display name, icon, color, and place counts (placeCount = directly in that category, totalPlaces = rolled up across its subtree). Use it to build a category browse/filter UI; the slug of any category is what places carry as canonicalCategorySlug.

curl -s "https://navvo.io/api/v1/places/categories" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "provider": "navvo-places", "count": 500, "rootCount": 38,
  "categories": [
    { "slug": "restaurants", "nameEn": "Restaurants", "nameAr": "مطاعم",
      "iconName": "restaurant", "color": "#386BFF",
      "placeCount": 9, "totalPlaces": 9, "children": [] },
    { "slug": "automotive", "nameEn": "Automotive", "placeCount": 0, "totalPlaces": 0,
      "children": [ { "slug": "car-rental", "nameEn": "Car Rental", "placeCount": 0, "totalPlaces": 0, "children": [] } ] }
  ]
}
FieldTypeNotes
countnumbertotal categories in the taxonomy
rootCountnumbernumber of top-level categories
categories[]arraytop-level nodes, each recursive with children
…placeCountnumberplaces directly assigned to this category
…totalPlacesnumberrolled-up count including all descendant categories

POST /places/reachable

"What's reachable" — every place you can get to from an origin within a travel-time budget. Navvo computes the isochrone (the reachability polygon) for the time/mode, then returns the places that fall inside it — not just within a circle, so it respects the real road & footpath network. Optional name/category/amenity filters apply on top.

FieldTypeNotes
origin{lat,lng}required — where you're starting from
minutesnumbertravel-time budget (default 15; max 60)
costingstringtravel mode: pedestrian (default), auto, bicycle
qstringoptional name filter
categoriesstringoptional comma-separated category keywords
amenitiesstringoptional comma-separated amenity slugs (all required, enabled)
limitnumbermax results (default 100; max 500)
curl -s -X POST "https://navvo.io/api/v1/places/reachable" \
  -H "x-api-key: $NAVVO_API_KEY" -H "content-type: application/json" \
  -d '{ "origin": {"lat":31.9539,"lng":35.9106}, "minutes": 15, "costing": "pedestrian", "categories": ["cafe"] }'
{
  "provider": "navvo-places", "available": true,
  "origin": { "lat": 31.9539, "lng": 35.9106 }, "minutes": 15, "costing": "pedestrian",
  "candidatesInBbox": 12, "count": 9,
  "reachable": [
    { "id": "", "slug": "", "name": "", "category": "cafe", "rating": 4.6, "lat": 31.95, "lng": 35.91 }
  ],
  "isochrone": { "type": "Polygon", "coordinates": [ /* … */ ] }
}

count is how many places are genuinely inside the reachability polygon (candidatesInBbox is the looser bounding-box prefilter — count ≤ it). The isochrone GeoJSON is returned so you can draw the reachable area on the map.


GET /places/{slug}

Full place detail: approved reviews & photos, questions + answers, and arrivalIntelligence.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe" \
  -H "x-api-key: nvvo_YOUR_KEY"

Path parameters

slug
string required
The unique place slug.

Response

In addition to all the fields from a list item, the detail response includes:

FieldTypeDescription
reviews[]arrayApproved reviews (rating, body, userId, …).
photos[]arrayActive, approved photos (url, caption, featured, …).
questions[]arrayQuestions with nested answers[].
reportsarrayAlways [] (never exposed).
arrivalIntelligenceobjectRecommended entrance and last-50-meters guidance (see below).
{
  "slug": "jordan-beans-cafe",
  "nameEn": "Jordan Beans Cafe",
  "center": "POINT(35.913 31.953)",
  "rating": "4.60",
  "entrances": [ { "id": "a1b2c3d4-…", "type": "main", "location": "POINT(35.9131 31.9529)" } ],
  "reviews": [ { "id": "r1…", "rating": 5, "body": "Great coffee.", "status": "approved" } ],
  "photos": [ { "id": "p1…", "url": "https://navvo.io/uploads/photo1.webp", "featured": true } ],
  "questions": [
    { "id": "q1…", "question": "Is there parking?", "status": "answered",
      "answers": [ { "id": "ans1…", "answer": "Yes, in the rear lot.", "ownerVerified": true } ] }
  ],
  "reports": [],
  "arrivalIntelligence": {
    "version": "navvo-arrival-v1",
    "placeCenter": { "lng": 35.913, "lat": 31.953 },
    "recommendedEntranceId": "a1b2c3d4-…",
    "candidates": [
      {
        "entranceId": "a1b2c3d4-…",
        "type": "main",
        "coordinates": { "lng": 35.9131, "lat": 31.9529 },
        "distanceFromPlaceMeters": 12,
        "score": 99,
        "recommended": true,
        "lastMetersGuidance": "12 meters from the place pin. Use this as the default arrival point for visitors.",
        "routeTarget": { "lat": 31.9529, "lng": 35.9131 }
      }
    ],
    "microMap": { "radiusMeters": 50, "title": "Last 50 meters", "guidance": "" }
  }
}
Arrival intelligence is what makes Navvo useful for delivery and ride-hail. Use arrivalIntelligence.candidates[0].routeTarget as the destination coordinate for routing instead of the place center — it points to the recommended entrance.

An unknown slug (or id) returns 404 Not Found.

Errors

StatusWhen
400Validation (e.g. limit > 100).
401 / 403Missing/invalid key, or key lacks the places scope.

GET /places/{slug}/hours

The opening-hours engine: a place's normalized weekly schedule, its live open/closed state, and the next open/close transition — all evaluated in Jordan time (Asia/Amman) and holiday-aware.

Navvo accepts hours in two shapes and normalizes both: our structured { "weekly": { "monday": "09:00-17:00", … } } map, and the raw OSM-style opening_hours string that imported POIs carry (e.g. "Mo-Fr 09:00-17:00; Sa 10:00-14:00; Su off", "24/7", lunch breaks like "Mo-Fr 08:00-12:00,13:00-18:00"). The engine returns a single canonical weekly map either way.

QueryTypeNotes
atISO datetimeoptional — evaluate at a future instant (trip planning); defaults to now
curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/hours" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe",
  "hasHours": true,
  "at": "2026-06-23T07:30:00.000Z",
  "weekly": {
    "monday": "09:00-17:00", "tuesday": "09:00-17:00", "wednesday": "09:00-17:00",
    "thursday": "09:00-17:00", "friday": "09:00-17:00", "saturday": "10:00-14:00", "sunday": "Closed"
  },
  "openState": "open",
  "openText": "Open · until 17:00",
  "nextChange": { "type": "closes", "dayOffset": 0, "weekday": "tuesday", "atMinutes": 1020, "time": "17:00", "label": "Open · closes 17:00" },
  "holiday": null
}
FieldTypeNotes
hasHoursbooleanfalse (with null fields) when the place has no hours data
weeklyobject | nullcanonical schedule — per day a comma-separated HH:MM-HH:MM list, or "Closed". "00:00-24:00" = all day
openStatestring | null"open", "closing" (≤45 min to close), "closed", or null
openTextstring | nullhuman label, e.g. "Open · until 17:00", "Closing soon · 17:00"
nextChangeobject | nullthe next transition within 7 days: type (opens/closes), weekday, time, dayOffset (0 = today, 1 = tomorrow), and a ready label
holidayobject | nullactive public holiday (hours annotated "… hours may vary", never hard-closed)
A ?at= in the future evaluates the schedule for that moment — useful for "will it be open when I arrive?" planning. Cross-midnight ranges (18:00-02:00) and Ramadan/holiday overlays are handled automatically.

GET /places/{slug}/popular-times

Google-style busyness for a place: the weekly hour-by-hour grid, the live "now" level, today's curve with its peak, and the quietest open hour ("best time to visit"). All evaluated in Jordan time. Busyness is 0–100.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/popular-times" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe", "hasData": true, "name": "Jordan Beans Cafe",
  "now": { "day": "Saturday", "hour": 19, "busyness": 50, "label": "A bit busy", "relative": "typical" },
  "today": {
    "day": "Saturday", "peakHour": 10,
    "curve": [18,31,31,43,50,50,43,31,37,43,43,37,31,37,50,75,81,93,75,62,62,43,31,25],
    "bestTimeToVisit": { "hour": 5, "busyness": 25, "label": "Not too busy" }
  },
  "weekly": { "Sunday": [/* 24 values */], "Monday": [/* … */] }
}
FieldTypeNotes
hasDatabooleanfalse (with null fields) when no popular-times exist for the place
nowobjectlive busyness (0–100) + human label + relative (near peak/typical/quieter than usual)
today.curvenumber24busyness per hour 0–23 for today; peakHour is its busiest hour
today.bestTimeToVisitobjectthe quietest open hour today — { hour, busyness, label }
weeklyobjectper-day 24-value busyness arrays (SundaySaturday)

Labels: Not busy (<25), Not too busy (<50), A bit busy (<70), Busy (<85), As busy as it gets (≥85).


GET /places/{slug}/attributes

The full structured "About" attributes for one place — every group (Accessibility, Parking, Payments, Service options, Amenities, …) with each option and whether it's enabled. This is the per-place detail; for catalogue-wide facets use GET /places/facets, and to filter places by amenity use ?amenities=.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/attributes" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe", "hasData": true, "name": "Jordan Beans Cafe",
  "groupCount": 2, "enabledCount": 4,
  "groups": [
    { "id": "payments", "name": "Payments", "options": [
      { "slug": "credit-cards", "label": "Credit cards", "enabled": true },
      { "slug": "nfc-mobile-payments", "label": "NFC mobile payments", "enabled": true }
    ]},
    { "id": "parking", "name": "Parking", "options": [
      { "slug": "on-site-parking", "label": "On-site parking", "enabled": true }
    ]}
  ]
}
FieldTypeNotes
hasDatabooleanfalse (with empty groups) when the place has no structured attributes
groups[].id / namestringattribute group (e.g. accessibility)
groups[].options[]array{ slug, label, enabled }enabled:false means the place explicitly lacks that feature (e.g. "Wheelchair-accessible entrance: no")
enabledCountnumbertotal enabled options across all groups

GET /places/{slug}/reviews-summary

The rating breakdown for a place — average, total review count, the most common star level, and the full 5★→1★ distribution with counts and percentages. Ideal for a ratings bar chart without fetching every review.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/reviews-summary" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe", "hasData": true, "name": "Jordan Beans Cafe",
  "average": 4.6, "totalReviews": 128, "mostCommonStars": 5,
  "distribution": [
    { "stars": 5, "count": 96, "percent": 75 },
    { "stars": 4, "count": 20, "percent": 15.6 },
    { "stars": 3, "count": 6, "percent": 4.7 },
    { "stars": 2, "count": 3, "percent": 2.3 },
    { "stars": 1, "count": 3, "percent": 2.3 }
  ]
}
FieldTypeNotes
hasDatabooleanfalse when the place has no rating/reviews
averagenumber | nullthe place's average rating (0–5)
totalReviewsnumbertotal number of reviews counted
mostCommonStarsnumberthe star level with the most reviews
distribution[]array{ stars, count, percent } for 5★ down to 1★ (percent of total)

GET /places/{slug}/photos

The photo gallery for a place — approved, active photos, featured first, paginated. Use it to render a place's image carousel.

QueryTypeNotes
pagenumber1-based page (default 1)
limitnumberpage size (default 30, max 100)
curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/photos?limit=20" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe", "name": "Jordan Beans Cafe",
  "total": 6, "page": 1, "limit": 20, "count": 6,
  "photos": [
    { "id": "", "url": "/uploads/places/…/a59e624b.webp", "caption": "Latest", "featured": true, "mediaType": "image", "createdAt": "2026-05-…" }
  ]
}
FieldTypeNotes
totalnumbertotal approved photos for the place
countnumberphotos on this page
photos[].urlstringimage URL (relative to the Navvo host)
photos[].featuredbooleanfeatured photos are returned first
photos[].captionstring | nulloptional caption

Only approved, active photos are returned (moderation applies). An unknown slug returns total: 0 with an empty photos array.


GET /places/{slug}/nearby

Other places near this one — a "similar places nearby" / "more like this" list, sorted by distance and excluding the place itself. Optionally restrict to the same category.

QueryTypeNotes
radiusKmnumbersearch radius (default 3, max 50)
sameCategoryboolean1/true → only places sharing the anchor's category
limitnumbermax results (default 20, max 100)
curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/nearby?radiusKm=3&sameCategory=1" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe", "center": { "lat": 31.95, "lng": 35.91 },
  "radiusKm": 3, "sameCategory": true, "anchorCategory": "cafe", "count": 2,
  "places": [
    { "slug": "", "name": "", "category": "cafe", "rating": 4.5, "distanceKm": 0.4 }
  ]
}
FieldTypeNotes
anchorCategorystring | nullthe category of the place you asked about
places[].distanceKmnumberstraight-line distance from the anchor place

GET /places/{slug}/entrances

The place's entrances/gates as a lightweight standalone read — the companion to the entrances[] embedded on the place detail, so a navigation client can refresh gates without refetching the whole place.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/entrances" \
  -H "x-api-key: $NAVVO_API_KEY"
{
  "slug": "jordan-beans-cafe",
  "items": [
    { "id": "a1b2c3d4-…", "type": "main", "label": "Main Entrance", "location": "POINT(35.9131 31.9529)" }
  ],
  "total": 1
}

items is empty (total: 0) when no dedicated entrances are configured — route to the place pin in that case. An unknown slug returns 404.


GET /places/{slug}/questions

The public Q&A thread for a place — questions with their answers, newest first. Read-only for API consumers; asking and answering are signed-in user features.

curl -s "https://navvo.io/api/v1/places/jordan-beans-cafe/questions" \
  -H "x-api-key: $NAVVO_API_KEY"
[
  {
    "id": "", "question": "Is there outdoor seating?", "status": "answered", "createdAt": "",
    "answers": [
      { "id": "", "answer": "Yes — a shaded terrace.", "ownerVerified": true, "createdAt": "" }
    ]
  }
]

The response is a plain array (empty when there are no questions). answers[].ownerVerified marks replies from the verified business owner.


POST /places/suggest

"Add a missing place" — let signed-in users submit a place that isn't on the map yet. Submissions land in Navvo's moderation queue and are reviewed by an editor; nothing appears on the map until approved.

Requires a signed-in Navvo user (Authorization: Bearer <accessToken> — see Users & Sync), not an API key.

FieldTypeNotes
namestringrequired — place name (English)
nameArstringoptional Arabic name
lat / lngnumberrequired — location
categorystringoptional category slug (see GET /places/categories)
phonestringoptional
websitestringoptional
notestringoptional — anything the reviewer should know
curl -s -X POST "https://navvo.io/api/v1/places/suggest" \
  -H "authorization: Bearer $NAVVO_USER_TOKEN" -H "content-type: application/json" \
  -d '{ "name": "Abu Ahmad Falafel", "nameAr": "فلافل أبو أحمد", "lat": 31.9539, "lng": 35.9106, "category": "restaurants" }'
{ "ok": true, "id": "", "status": "quarantined", "note": "Thanks! Your suggestion is queued for review." }

status is always quarantined on intake — the suggestion is held for review. Missing name or non-numeric lat/lng returns 400.


User-authored content

Writing reviews, photos, questions, and reports is a first-party, end-user feature — those endpoints require a logged-in user session (Bearer JWT), not an API key, and are not part of the integration API. If your product needs user-generated content, contact Navvo to discuss partner access.

Copyright © 2026