> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/routes-api/overview.md).

# Overview

Push GPS routes to your users' Garmin, COROS, Wahoo and Hammerhead devices.

The Routes API pushes GPS courses to your users' fitness devices, so they don't have to recreate them by hand on their watch or bike computer. Your app can:

* **Create reusable route templates**: define the route once, with its waypoints.
* **Push to any user**: send the route to a user's connected device.
* **Keep devices up to date**: an update to the template reaches every user it was pushed to.

Routes work with Garmin, COROS, Wahoo and Hammerhead. Not every provider supports every operation; see [Provider compatibility](/routes-api/provider-compatibility.md).

Routes are part of the [Planned Workouts add-on](/planned-workouts-api/pricing.md). Each push, and each pushed route an update re-sends, costs 10 Planned Workouts credits, like a workout push. Reads and deletes are free. Without the add-on, every Routes endpoint except the deletes returns `403 Forbidden`.

## How it works

You create a route template once, then push it to each user.

```
┌─────────────────────────────────────────────────────────────────┐
│  Phase 1: Create Template (once)                                │
│  POST /routes                                                   │
│  → Returns route_id                                             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│  Phase 2: Push to User                                          │
│  POST /routes/{route_id}/push?user_id=X                         │
│  → Sends the route to the user's provider                       │
│  → Appears on the user's device after its next sync             │
└─────────────────────────────────────────────────────────────────┘
```

## Authentication

Every request needs two headers:

| Header      | Description       |
| ----------- | ----------------- |
| `dev-id`    | Your developer ID |
| `x-api-key` | Your API key      |

## Quickstart

### Create a route template

Create a simple running loop:

```bash
curl -X POST "https://access.tryterra.co/api/v2/routes" \
  -H "Content-Type: application/json" \
  -H "dev-id: YOUR_DEV_ID" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "name": "Morning Run Loop",
    "sport": "running",
    "waypoints": [
      { "latitude": 51.5074, "longitude": -0.1278, "elevation_meters": 10 },
      { "latitude": 51.5120, "longitude": -0.1220, "elevation_meters": 30 },
      { "latitude": 51.5160, "longitude": -0.1180, "elevation_meters": 55 },
      { "latitude": 51.5120, "longitude": -0.1140, "elevation_meters": 70 },
      { "latitude": 51.5074, "longitude": -0.1278, "elevation_meters": 10 }
    ]
  }'
```

Response (`200 OK`):

```json
{
  "status": "success",
  "route_id": "295581149349019648"
}
```

Distance comes from the waypoints, and elevation gain and loss are worked out from them when every waypoint has `elevation_meters`.

### Push it to a user

```bash
curl -X POST "https://access.tryterra.co/api/v2/routes/295581149349019648/push?user_id=USER_ID" \
  -H "dev-id: YOUR_DEV_ID" \
  -H "x-api-key: YOUR_API_KEY"
```

Response (`201 Created`):

```json
{
  "status": "success",
  "pushed_route_id": "295581443239706624",
  "provider_route_id": "1774538415035"
}
```

The route appears on the user's device after its next sync. Keep `pushed_route_id`: it is Terra's ID for this user's copy of the route.

Pushing the same route to the same user again re-sends their pushed route instead of adding a second one. It returns `200 OK` with the same `pushed_route_id`.

## API endpoints

| Method | Endpoint                                    | Description                                                     |
| ------ | ------------------------------------------- | --------------------------------------------------------------- |
| POST   | `/routes`                                   | Create a route template                                         |
| GET    | `/routes`                                   | List your route templates                                       |
| PUT    | `/routes/{route_id}`                        | Update a template and re-send it to every user it was pushed to |
| DELETE | `/routes/{route_id}`                        | Remove the route from every user's device, then delete it       |
| POST   | `/routes/{route_id}/push?user_id=X`         | Push a route to a user's device                                 |
| GET    | `/pushedRoutes?user_id=X`                   | List the routes pushed to a user                                |
| GET    | `/pushedRoutes/{pushed_route_id}?user_id=X` | Get one pushed route                                            |
| DELETE | `/pushedRoutes/{pushed_route_id}?user_id=X` | Remove a route from one user's device                           |

`user_id` is the Terra user ID of one provider connection, as for the rest of the API.

## Next steps

* [Core concepts](/routes-api/core-concepts.md): route templates, waypoints, pushed routes, updates, deletes, errors and validation
* [Sport-specific examples](/routes-api/sport-specific-examples.md): copy-paste routes for running, trail running, hiking and cycling
* [Provider compatibility](/routes-api/provider-compatibility.md): what Garmin, COROS, Wahoo and Hammerhead support
