Navvo
Guides

Go SDK

Install and use the official github.com/navvo/navvo-go client for server-side geocoding, routing, places, traffic, EV, transit, and more.

Go SDK

The official github.com/navvo/navvo-go module (package navvo) is a server-side Go client for the Navvo Web Service. It is fully typed, retry-aware, concurrency-safe, and uses only the standard library (net/http, encoding/json, context) — no third-party dependencies. Every call takes a context.Context first argument. There is no map UI or tile rendering — for rendering a map in the browser use Navvo Maps.

Requires: Go 1.21+ · Base URL: https://navvo.io/api/v1

Install

go get github.com/navvo/navvo-go
import navvo "github.com/navvo/navvo-go"

Authenticate

Every call is sent with the x-api-key header. Pass the key explicitly, or pass "" to read it from the NAVVO_API_KEY environment variable. The key shape (nvvo_<48 hex>) is validated up front.

c, err := navvo.New("")                    // uses $NAVVO_API_KEY
c, err := navvo.New("nvvo_your_key_here")  // explicit

The SDK never puts the key in a URL — except StyleURL(), which builds a browser-fetchable map style URL where the key must ride as ?api_key= (browsers cannot set headers on tile/style requests).

Quickstart

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    navvo "github.com/navvo/navvo-go"
)

func main() {
    c, err := navvo.New("") // reads NAVVO_API_KEY
    if err != nil {
        log.Fatal(err)
    }
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Forward geocode — string coordinates are parsed to numbers for you.
    hits, err := c.Geocode(ctx, "Abdali Hospital, Amman", &navvo.GeocodeOptions{Limit: 5})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(hits[0].Lat, hits[0].Lng, hits[0].DisplayName)

    // Plan a route — you pass {Lat, Lng}; the SDK serialises lon/lat on the wire.
    plan, err := c.Route(ctx, navvo.RoutePlanRequest{
        Locations: []navvo.LatLng{
            {Lat: 31.95, Lng: 35.91, Name: "A"},
            {Lat: 31.99, Lng: 35.95, Name: "B"},
        },
        Costing: "auto",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("ETA seconds:", plan.Trip().Summary.Time)

    // Decode the leg polyline (polyline6) into points.
    line := plan.Geometry()
    fmt.Println("shape points:", len(line))

    // Live, condition-aware extras.
    wx, _ := c.WeatherPoint(ctx, 31.95, 35.91, "metric")
    fmt.Println(wx.Temperature, wx.Unit, "·", *wx.AQICategory)
}

Configuration

New accepts functional options:

c, err := navvo.New(
    "",
    navvo.WithBaseURL("https://navvo.io/api/v1"),
    navvo.WithTimeout(15*time.Second),
    navvo.WithUserAgent("acme-dispatch/2.3"),
    navvo.WithRetry(navvo.RetryConfig{
        Retries: 3, BaseDelay: 500 * time.Millisecond, Factor: 2, Jitter: true, MaxDelay: 20 * time.Second,
    }),
)

Use navvo.WithHTTPClient(myClient) to bring your own pooled *http.Client, and c.WithAPIKey(key) to clone a client for a different key (multi-tenant servers). A *Client is safe for concurrent use across goroutines.

Coordinates — never backwards

You always supply points as navvo.LatLng{Lat, Lng}. The SDK owns every wire-format difference: {lon, lat} for Route/TrafficRoute, {lat, lon} for the routing passthrough payloads (SimpleRoute/Matrix/Optimize), separate lat/lon params for reverse geocode, west,south,east,north for BBox, [lng, lat] for GeoJSON, and WKT POINT(lng lat) for place center (parse it with navvo.ParseWKTPoint(place.Center) or place.CenterLatLng()).

amman := navvo.LatLng{Lat: 31.9539, Lng: 35.9106}
box := navvo.BBox{West: 35.85, South: 31.92, East: 35.98, North: 32.02}

Retries & errors

Transient failures (5xx, 408, 429/quota, network blips, and available:false envelopes) are retried with exponential backoff and full jitter, honouring Retry-After; client errors (400/401/403/404) are never retried. Every error wraps *navvo.APIError and supports errors.Is / errors.As:

hits, err := c.Geocode(ctx, "Abdali Hospital, Amman", nil)
if err != nil {
    var rl *navvo.RateLimitError
    var scope *navvo.ScopeError
    switch {
    case errors.As(err, &rl):
        log.Printf("rate limited, retry after %v", rl.RetryAfter)
    case errors.As(err, &scope):
        log.Printf("scope/quota problem: %s (missing %s)", scope.Reason, scope.Scope)
    case errors.Is(err, navvo.ErrServiceUnavailable):
        log.Print("geocoder upstream is down — fall back")
    default:
        return err
    }
}

The geocoder/routing envelope ({ provider, available, data }) is unwrapped for you — an available:false body becomes a *navvo.ServiceUnavailableError — and an unknown place slug returns nil (a soft-null, not an error). Cancel or deadline any call through the context.Context you pass.

ErrorSentinelFrom
*ConfigErrorErrConfigbad/missing key, bad option
*ValidationErrorErrValidation400 (has Fields)
*AuthErrorErrUnauthorized401
*ScopeErrorErrForbidden403 (has Reason, Scope)
*NotFoundErrorErrNotFound404
*RateLimitErrorErrRateLimited429 (has RetryAfter)
*ServiceUnavailableErrorErrServiceUnavailableavailable:false, 502/503
*ServerErrorErrServerother 5xx
*TimeoutError / *NetworkErrorErrTimeout / ErrNetworktimeout / transport

The API key is sent only in the x-api-key header and never appears in an error; errors carry RedactedKey (nvvo_****<last4>).

Method map

AreaMethods
Tiles & configStyles, StyleURL, MapConfig
Search & geocodingSearch, Geocode, ReverseGeocode, GeocodeBatch
PlacesListPlaces, Place, PlaceThumb, PlaceCategories
RoutingRoute, SimpleRoute, Matrix, Optimize, RoutingProfiles
Traffic & incidentsTrafficRoute, TrafficSummary, Incidents, IncidentTypes, ReportIncident, RoadEdits, RouteRisk
Weather & air qualityWeatherPoint, WeatherForecast, WeatherCities, AirQualityCities
EV & transitEVStations, TransitStops, GBFS

Each method maps to the endpoint documented in the API reference. Results expose a Raw field (map[string]any) with the full untyped body for forward compatibility. Optimize requires the opt-in optimize scope; TrafficRoute requires both routing and traffic. See Route Optimization and Traffic & Incidents.

Publishing & versioning

The module is published via Git tags. The current version is v0.1.0:

go get github.com/navvo/navvo-go@v0.1.0
Copyright © 2026