Atlas provides authenticated Moroccan place search, OpenStreetMap feature search, and driving routes through the standard Sawalni API.
https://api.sawalni.com/v1/atlas
All endpoints use a Sawalni bearer key:
Authorization: Bearer YOUR_API_KEY
Atlas is real-data-only. Search uses the Morocco locality and local OSM indexes; routing returns live OSRM geometry and instructions. The service does not synthesize fallback places or routes.
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /v1/atlas/search | Cross-script locality search with optional streets and POIs |
| GET | /v1/atlas/osm/search | Search the local OSM feature index directly |
| GET | /v1/atlas/route | Driving route geometry and turn instructions |
| GET | /v1/atlas/stats | Locality index inventory and script coverage |
| GET | /v1/atlas/models | Loaded model and channel metadata |
| GET | /v1/atlas/health | Service health and loaded-index counts |
GET /v1/atlas/search
Atlas accepts Arabic, Tifinagh, French, Arabizi, local spellings, descriptive aliases, and phonetic approximations.
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | required | Place, street, landmark, nickname, or local spelling |
model | string | sawtone-v4 | Only sawtone-v4 is supported |
channel | string | composite | composite, phonetic, ortho, or semantic |
limit | integer | 50 | 1–200; interactive clients should normally request 5–12 |
place_type | string | — | Comma-separated locality types such as city,town,village |
name_filter | string | — | Optional literal name fragment |
include_streets | boolean | false | Include the local OSM feature index in candidate generation |
curl --get 'https://api.sawalni.com/v1/atlas/search' \ -H 'Authorization: Bearer YOUR_API_KEY' \ --data-urlencode 'q=l3rayech' \ --data 'model=sawtone-v4' \ --data 'channel=composite' \ --data 'limit=5'
{ "query": "l3rayech", "original_query": "l3rayech", "intent": { "query_type": "literal", "query_candidates": ["l3rayech"] }, "provider": "combined", "total_candidates": 7339, "search_time_ms": 1121.0, "ranking": { "strategy": "destination-first-v3", "candidate_pool": 120, "result_limit": 5, "population_missing_fallback": "place_type", "result_groups": { "preferred": 1, "local": 1, "discarded": 78 } }, "process": [ { "id": "interpret", "label": "Interpreted the request", "status": "complete" }, { "id": "retrieve", "label": "Retrieved geographic candidates", "status": "complete" }, { "id": "match", "label": "Matched across scripts", "status": "complete" }, { "id": "rank", "label": "Ranked likely destinations", "status": "complete" } ], "results": [ { "id": "sawtone:…", "source": "sawtone", "name": "Larache", "name_ar": "العرائش", "name_ti": "ⵍⵄⵔⴰⵢⵛ", "kind": "city", "lat": 35.19, "lon": -6.15, "population": 107371, "result_tier": "primary", "result_rank": 1, "match": { "confidence": "medium", "prominence": 0.9191, "prominence_relevance_gate": 0.8811, "signals": ["City", "Known population"] } } ] }
The process array reports observable operations, not chain-of-thought. match.signals is safe to show as a concise explanation of result ordering.
Atlas first classifies the request as literal or descriptive. Literal names go directly to cross-script retrieval. Descriptions are rewritten into one concise geographic query, then Atlas selects a result compatible with the planned entity type. The public intent contains the bounded query plan, never private reasoning. Al/El + X and fused AlX/ElX spellings are generated bidirectionally and encoded in one Sawtone batch; for example, El Ayoun, ElAyoun, and Laayoune can participate in the same search.
Atlas retrieves an oversized candidate pool, preserves name and intent relevance, and uses locality type, logarithmic known population, and external geographic importance to resolve close ambiguity. A destination-selection pass then returns a compact set annotated as primary, alternative, or local. Villages, hamlets, and isolated dwellings move to the local tier when a stronger city/town interpretation exists. Navigation and POI intent automatically searches the real OSM index. Exact small-locality queries retain their exact-match advantage.
Population is sparse in the source dataset and is never the sole definition of importance. Missing values fall back to the OSM locality hierarchy.
GET /v1/atlas/osm/search
Use this endpoint when you explicitly want streets, stations, amenities, and other named OSM features.
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | required | Named OSM feature query |
model | string | sawtone-v4 | Sawtone v4 only |
channel | string | composite | Matching channel |
limit | integer | 8 | 1–20 |
curl --get 'https://api.sawalni.com/v1/atlas/osm/search' \ -H 'Authorization: Bearer YOUR_API_KEY' \ --data-urlencode 'q=Avenue Mohammed V Rabat' \ --data 'limit=5'
GET /v1/atlas/route
| Parameter | Type | Description |
|---|---|---|
start_lat | number | Origin latitude |
start_lon | number | Origin longitude |
end_lat | number | Destination latitude |
end_lon | number | Destination longitude |
curl --get 'https://api.sawalni.com/v1/atlas/route' \ -H 'Authorization: Bearer YOUR_API_KEY' \ --data 'start_lat=34.02236' \ --data 'start_lon=-6.8340222' \ --data 'end_lat=31.6258257' \ --data 'end_lon=-7.9891608'
{ "distance": 321900.4, "duration": 13260.2, "geometry": [[-6.8340, 34.0223], [-6.8338, 34.0219]], "steps": [ { "instruction": "Head right on the road", "distance": 74.0, "duration": 12.4, "name": "" } ], "route_time_ms": 814.1 }
Coordinates in geometry are GeoJSON order: [longitude, latitude]. Distances are meters and durations are seconds.
curl 'https://api.sawalni.com/v1/atlas/stats' -H 'Authorization: Bearer YOUR_API_KEY' curl 'https://api.sawalni.com/v1/atlas/models' -H 'Authorization: Bearer YOUR_API_KEY' curl 'https://api.sawalni.com/v1/atlas/health' -H 'Authorization: Bearer YOUR_API_KEY'
Health responses report the loaded model and current locality/OSM counts. Models reports sawtone-v4 and its channel dimensions. Stats reports place types plus Arabic and Tifinagh coverage.
Atlas uses simple per-request pricing. Failed requests are not charged, and the internal Sawtone lookup is included rather than billed as a second customer-facing operation.
| Operation | Credits |
|---|---|
/atlas/search | 1 credit per request |
/atlas/search?include_streets=true | 2 credits per request |
/atlas/osm/search | 1 credit per request |
/atlas/route | 0.5 credit per request |
/atlas/stats, /atlas/models, /atlas/health | Free |
One credit is approximately $0.01 at the standard portal conversion shown on the Billing page.
const params = new URLSearchParams({ q: "ⵜⵉⵣⵏⵉⵜ", model: "sawtone-v4", channel: "composite", limit: "5" }); const response = await fetch( "https://api.sawalni.com/v1/atlas/search?" + params, { headers: { Authorization: "Bearer YOUR_API_KEY" } } ); if (!response.ok) throw new Error(await response.text()); const atlas = await response.json(); console.log(atlas.results[0]);
| HTTP code | Meaning |
|---|---|
| 401 | Missing or invalid Sawalni API key |
| 404 | Unsupported Atlas operation |
| 422 | Invalid query parameters or unsupported model/channel |
| 429 | Atlas is at its concurrency limit; retry with backoff |
| 502 | A geographic or routing dependency failed |
| 503 | No healthy Atlas deployment is available |
| 504 | The Atlas service timed out |
Do not silently replace 5xx responses with fabricated locations or estimated routes. Preserve the error and let users retry, refine the query, or use a non-search map fallback.