> ## Documentation Index
> Fetch the complete documentation index at: https://docs.footstep.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> First API calls for routing and geocoding

This guide covers routing between two coordinates and geocoding an address. You'll need an API key from [console.footstep.ai](https://console.footstep.ai).

## Get an API key

Sign up at [console.footstep.ai](https://console.footstep.ai) and create an API key. Your key will look like `sk_live_abc123...`. Keep it safe, as it's used to authenticate every request.

<Warning>
  API keys are for server-side use only. Never expose them in frontend code, mobile apps, or anywhere a user could inspect network traffic.
</Warning>

## Your first request

Every routing request needs at least two locations: a start and an end. Each location is a `lat`/`lon` pair. Here's a route from King's Cross to Tower Bridge in London:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.footstep.ai/v1/routing/route \
    -H "x-api-key: sk_live_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "locations": [
        { "lat": 51.5322, "lon": -0.1240 },
        { "lat": 51.5055, "lon": -0.0754 }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.footstep.ai/v1/routing/route", {
    method: "POST",
    headers: {
      "x-api-key": "sk_live_your_key_here",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      locations: [
        { lat: 51.5322, lon: -0.1240 },
        { lat: 51.5055, lon: -0.0754 },
      ],
    }),
  });

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.footstep.ai/v1/routing/route",
      headers={"x-api-key": "sk_live_your_key_here"},
      json={
          "locations": [
              {"lat": 51.5322, "lon": -0.1240},
              {"lat": 51.5055, "lon": -0.0754},
          ]
      },
  )

  data = response.json()
  ```
</CodeGroup>

The defaults return a car route with terrain analytics. You can change this with the `travel` parameter.

## Understand the response

The response contains a `route` object with everything you need:

```json theme={null}
{
  "route": {
    "distance_meters": 5765,
    "duration_seconds": 812,
    "terrain": {
      "total_ascent_meters": 12.4,
      "total_descent_meters": 8.1,
      "max_elevation_meters": 28,
      "min_elevation_meters": 5,
      "avg_grade_percent": 1.2,
      "max_grade_percent": 4.5,
      "elevation_profile": [
        { "distance_meters": 0, "elevation_meters": 22 },
        { "distance_meters": 500, "elevation_meters": 18 },
        { "distance_meters": 1000, "elevation_meters": 15 }
      ],
      "difficulty": "flat"
    },
    "legs": [
      {
        "distance_meters": 5765,
        "duration_seconds": 812,
        "steps": [
          {
            "instruction": "Drive north on Midland Road.",
            "distance_meters": 120,
            "duration_seconds": 15
          }
        ]
      }
    ]
  }
}
```

Here's what the key fields mean:

| Field                          | What it tells you                                                    |
| ------------------------------ | -------------------------------------------------------------------- |
| `distance_meters`              | Total route distance in meters                                       |
| `duration_seconds`             | Estimated travel time in seconds                                     |
| `terrain.total_ascent_meters`  | Total climbing over the route in meters                              |
| `terrain.total_descent_meters` | Total descending over the route in meters                            |
| `terrain.elevation_profile`    | Array of distance/elevation points for charting                      |
| `terrain.difficulty`           | Overall classification: `flat`, `rolling`, `hilly`, or `mountainous` |
| `legs[].steps[]`               | Turn-by-turn directions with distance and time per manoeuvre         |

<Note>
  All field names include their unit. `distance_meters` is always meters, `duration_seconds` is always seconds, `grade_percent` is always a percentage. This is true regardless of the `units` parameter you send in the request.
</Note>

## Change how you travel

The default is `auto` (car). You can switch to walking, cycling, or other travel types using the `travel` parameter:

```json theme={null}
{
  "locations": [
    { "lat": 51.5322, "lon": -0.1240 },
    { "lat": 51.5055, "lon": -0.0754 }
  ],
  "travel": "pedestrian"
}
```

| Travel       | Use case                                                     |
| ------------ | ------------------------------------------------------------ |
| `auto`       | Car routing (default)                                        |
| `pedestrian` | Walking and hiking. Factors in terrain, avoids motorways     |
| `bicycle`    | Cycling. Considers surface type and hill gradients           |
| `bus`        | Bus routing                                                  |
| `truck`      | Truck routing. Respects vehicle dimensions and weight limits |

Each travel type produces different routes and terrain analytics. A `pedestrian` route through hilly terrain will show significantly different `difficulty` and grade profiles compared to the same coordinates with `auto`.

## Try GeoJSON format

By default, responses use the `footstep` format, which is compact JSON with encoded polyline geometry. If you're working with mapping libraries or GIS tools, you can request GeoJSON instead:

```json theme={null}
{
  "locations": [
    { "lat": 51.5322, "lon": -0.1240 },
    { "lat": 51.5055, "lon": -0.0754 }
  ],
  "format": "geojson"
}
```

This returns a standard [GeoJSON FeatureCollection](https://datatracker.ietf.org/doc/html/rfc7946) with decoded coordinate arrays. You can paste the response directly into [geojson.io](https://geojson.io) to visualise it, or load it into Leaflet, Mapbox GL, deck.gl, or QGIS without any transformation.

## Try geocoding

Geocoding converts text into coordinates. Search for any address, place, or landmark:

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.footstep.ai/v1/geocoding/search?text=Buckingham+Palace" \
    -H "x-api-key: sk_live_your_key_here"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.footstep.ai/v1/geocoding/search?text=Buckingham+Palace",
    { headers: { "x-api-key": "sk_live_your_key_here" } }
  );

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.footstep.ai/v1/geocoding/search",
      headers={"x-api-key": "sk_live_your_key_here"},
      params={"text": "Buckingham Palace"},
  )

  data = response.json()
  ```
</CodeGroup>

Every result includes a confidence score and place type:

```json theme={null}
{
  "results": [
    {
      "coordinates": { "lat": 51.5014, "lng": -0.1419 },
      "label": "Buckingham Palace, London, England, United Kingdom",
      "name": "Buckingham Palace",
      "confidence": 0.95,
      "place_type": "venue"
    }
  ]
}
```

Use `focus.point` to bias results towards a location (e.g. the user's city) and `boundary.country` to restrict to specific countries. See the [geocoding guide](/api/geocoding) for the full set of parameters and endpoints.

## Next steps

<Columns cols={2}>
  <Card title="Routing API" icon="route" href="/api/routing">
    Terrain-intelligent routing, elevation, and spatial analysis.
  </Card>

  <Card title="Geocoding API" icon="magnifying-glass" href="/api/geocoding">
    Search, reverse geocode, autocomplete, and batch processing.
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    How API keys work, key states, and security practices.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/errors">
    Error codes, what triggers them, and how to handle retries.
  </Card>
</Columns>
