# Afdal API v2 guide

One base URL, `https://api.afdal.tech`, covers place search, road routing, and driving-route optimization. Use the same `X-API-Key` for all three. Afdal handles the routing and optimization behind this API.

The routes and optimization results include road-following GeoJSON. Request points use named `lat` and `lon` fields; GeoJSON coordinates are always `[longitude, latitude]` as required by the format.

## Start here

```bash
export AFDAL_API_KEY='YOUR_KEY'
curl -s https://api.afdal.tech/api/v2/modes
curl -s https://api.afdal.tech/api/v2/route \
  -H "X-API-Key: $AFDAL_API_KEY" -H 'Content-Type: application/json' \
  -d '{"mode":"drive","points":[{"lat":33.8938,"lon":35.5018},{"lat":33.9808,"lon":35.6178}]}'
```

The runnable examples and tutorial notebook are bundled in [`afdal-v2-playground.zip`](afdal-v2-playground.zip). Additional v2 Python examples are in [`unified_api_examples.py`](unified_api_examples.py).

## Endpoint order

| Step | Endpoint | Purpose | API key |
| --- | --- | --- | --- |
| 1 | `GET /api/v2/modes` | Discover `drive` and `walk` routing modes. Optimization supports only `drive`. | No |
| 2 | `POST /api/v2/route` | Route through two or more points in the given order. | Yes |
| 3 | `POST /api/v2/optimize` | Choose stop order and vehicles, then return full driving geometry for each route. | Yes |
| Optional | `GET /api/v2/geocode` | Search addresses and points of interest (POIs). | Yes |

All distances are metres and durations are seconds, except planning clock fields, which are minutes from midnight. Times are estimates without live traffic.

## Road routing

`POST /api/v2/route` accepts `mode: "drive"` or `"walk"` and an ordered `points` array. It never reorders points.

```json
{
  "mode": "walk",
  "points": [
    {"lat": 36.7992, "lon": 10.1801},
    {"lat": 36.8038, "lon": 10.1834}
  ]
}
```

The response includes `distance_m`, `duration_s`, `geometry` (a GeoJSON `LineString`), `coordinates` (the same `[lon, lat]` pairs for simple drawing), `legs`, and `road_access` (where each point snapped to a road). Afdal returns an error if no road connection is available. Long requests are returned as one continuous route.

## Driving optimization with geometry

`POST /api/v2/optimize` accepts only `mode: "drive"`. `load` and fleet `capacity` use the same integer unit: parcels, seats, or another unit you choose. A stop ID is optional; the API assigns `stop-1`, `stop-2`, and so on when omitted. IDs must be unique.

```json
{
  "mode": "drive",
  "depot": {"lat": 33.8938, "lon": 35.5018},
  "stops": [
    {"id": "A1", "address": "Hamra", "lat": 33.8963, "lon": 35.4841, "load": 2, "phone": "+33783719427"},
    {"id": "A2", "address": "Achrafieh", "lat": 33.8884, "lon": 35.5198, "load": 1,
     "window_start": 540, "window_end": 720}
  ],
  "fleet": {"vehicles": 1, "capacity": 4},
  "planning": {"start_minute": 480, "end_minute": 1140,
               "service_minutes": 5, "time_limit_seconds": 10,
               "end_policy": "depot", "service_profile": "delivery"}
}
```

`planning` and `fleet` may be omitted to use their defaults. `window_start` and `window_end` must be supplied together and are absolute minutes from midnight (`540` means 09:00). Unspecified stop windows span the planning day. `end_policy` is `depot` (return) or `open` (finish at the last stop). `service_profile` can be `delivery`, `pickup`, or `none`.

The response has one entry per used vehicle. Each contains the ordered `stops` (including depot/finish points), their IDs, phone numbers and arrival minutes, `distance_m`, `duration_s`, `geometry`, and `coordinates`. `total_distance_m` sums the returned road geometries; `unassigned_stop_ids` lists stops that could not be assigned. Routing metadata uses the Afdal name.

Optimization uses road distances. It does not substitute straight-line distances when road routing is unavailable. Large requests may require supported regional coverage.

## Address and POI search

`GET /api/v2/geocode?q=Beirut%20airport` returns `{ "results": [...] }`, with entries containing `name`, `label`, `lat`, and `lon`. Add both `focus_lat` and `focus_lon` to bias results near a location. This is search/geocoding, not reverse geocoding. Place-search availability and freshness may differ from road routing.

Map tiles are not part of this release. The map UI still obtains its tiles from its configured provider; proxying them through this API would require a separate cache, usage policy, and attribution review.

## Authentication, limits, and errors

Send `X-API-Key: YOUR_KEY` on routing, optimization, and geocoding requests. A successful call consumes one query from that key's quota; discovery via `/modes` is free. Standard keys accept at most 99 locations per routing or optimization request, counting the depot. Ask Afdal if your integration needs a higher limit. Large road requests require supported regional coverage.

Invalid keys return `401`; inactive keys return `403`; expired or exhausted keys return `402`. Location-limit failures return `413`, malformed input `422`, disconnected routes `422`, and unavailable routing `503`. API-key errors contain `detail.code`, `detail.message`, and `detail.support_url`; other errors contain a readable `detail` string. Do not retry a disconnected-route error with the same points.

## Guided playground

Download [`afdal-v2-playground.zip`](afdal-v2-playground.zip) for four progressive requests: point-to-point routing; several stops with one vehicle; several stops with two vehicles; and two vehicles with stop time windows and equal capacity. The bundle contains editable JSON, a standard-library Python runner, a Jupyter notebook, a v2-only Postman collection, and a README. Every request in that package uses `/api/v2/*`.
