# Working with annotations

{% hint style="warning" %}

#### Note: Annotations were previously referred to as Elements.

References have been updated in the app and documentation, while naming in the REST API and JS SDK remains unchanged.
{% endhint %}

Annotations live at the top layer of a map, and are created directly inside the Felt app.

{% hint style="info" %}
Combining annotations with [webhooks](https://developers.felt.com/rest-api/listening-to-updates-using-webhooks) is a great way to create interactive data apps in Felt.
{% endhint %}

## Listing all annotations on a map

Annotations live at the top layer of a map, and are created directly inside the Felt app.

Annotations are returned as a [GeoJSON Feature Collection](https://geojson.org/).

{% tabs %}
{% tab title="curl" %}

```bash
# Your API token and map ID should look like this:
# FELT_API_TOKEN="felt_pat_ABCDEFUDQPAGGNBmX40YNhkCRvvLI3f8/BCwD/g8"
# MAP_ID="CjU1CMJPTAGofjOK3ICf1D"
FELT_API_TOKEN="<YOUR_API_TOKEN>"
MAP_ID="<YOUR_MAP_ID>"

curl -L \
  -H "Authorization: Bearer ${FELT_API_TOKEN}" \
  "https://felt.com/api/v2/maps/${MAP_ID}/elements"
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

# Your API token and map ID should look like this:
# api_token = "felt_pat_ABCDEFUDQPAGGNBmX40YNhkCRvvLI3f8/BCwD/g8"
api_token = "<YOUR_API_TOKEN>"
map_id = "<YOUR_MAP_ID>"

r = requests.get(
  f"http://felt.com/api/v2/maps/{map_id}/elements",
  headers={"Authorization": f"Bearer {api_token}"}
)
assert r.ok
print(r.json())
```

{% endtab %}

{% tab title="felt-python" %}

```python
import os

from felt_python import list_elements

# Setting your API token as an env variable can save
# you from repeating it in every function call
os.environ["FELT_API_TOKEN"] = "<YOUR_API_TOKEN>"

map_id = "<YOUR_MAP_ID>"

list_elements(map_id)
```

{% endtab %}
{% endtabs %}

## Listing all annotation groups

Returns a list of GeoJSON Feature Collections, one for each annotation group.

{% tabs %}
{% tab title="curl" %}

```bash
curl -L \
  -H "Authorization: Bearer ${FELT_API_TOKEN}" \
  "https://felt.com/api/v2/maps/${MAP_ID}/element_groups"
```

{% endtab %}

{% tab title="Python" %}

```python
r = requests.get(
  f"http://felt.com/api/v2/maps/{map_id}/elements",
  headers={"Authorization": f"Bearer {api_token}"}
)
assert r.ok
print(r.json())
```

{% endtab %}

{% tab title="felt-python" %}

```python
from felt_python import list_element_groups

list_element_groups(map_id)
```

{% endtab %}
{% endtabs %}

## Create or update new annotations

Each annotation is represented by a feature in the `POST`ed GeoJSON Feature Collection.

For each feature, including an existing annotation ID (`felt:id`) will result in the annotation being updated on the map. If no annotation ID is provided (or a non-existent one) , a new annotation will be created.

{% tabs %}
{% tab title="curl" %}

```bash
curl -L \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${FELT_API_TOKEN}" \
  "https://felt.com/api/v2/maps/${MAP_ID}/elements" \
  -d '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"coordinates":[[[15.478752514432728,15.576176978045694],[15.478752514432728,4.005934587045303],[29.892174099255755,4.005934587045303],[29.892174099255755,15.576176978045694],[15.478752514432728,15.576176978045694]]],"type":"Polygon"}}]}'
```

{% endtab %}

{% tab title="Python" %}

```python
new_elements = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            [
              15.478752514432728,
              15.576176978045694
            ],
            [
              15.478752514432728,
              4.005934587045303
            ],
            [
              29.892174099255755,
              4.005934587045303
            ],
            [
              29.892174099255755,
              15.576176978045694
            ],
            [
              15.478752514432728,
              15.576176978045694
            ]
          ]
        ],
        "type": "Polygon"
      }
    }
  ]
}

r = requests.post(
  f"http://felt.com/api/v2/maps/{map_id}/elements",
  headers={"Authorization": f"Bearer {api_token}"},
  json=new_elements
)
assert r.ok
print(r.json())
```

{% endtab %}

{% tab title="felt-python" %}

```python
from felt_python import upsert_elements

new_elements = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            [
              15.478752514432728,
              15.576176978045694
            ],
            [
              15.478752514432728,
              4.005934587045303
            ],
            [
              29.892174099255755,
              4.005934587045303
            ],
            [
              29.892174099255755,
              15.576176978045694
            ],
            [
              15.478752514432728,
              15.576176978045694
            ]
          ]
        ],
        "type": "Polygon"
      }
    }
  ]
}

upsert_elements(map_id, new_elements)
```

{% endtab %}
{% endtabs %}

## Delete an annotation

Annotations can be deleted by referencing them by ID

{% tabs %}
{% tab title="curl" %}

```bash
curl -L \
  -X DELETE \
  -H "Authorization: Bearer ${FELT_API_TOKEN}" \
  "https://felt.com/api/v2/maps/${MAP_ID}/elements/{ELEMENT_ID}"
```

{% endtab %}

{% tab title="Python" %}

```python
element_id = "<YOUR_ELEMENT_ID>"

r = requests.delete(
  f"http://felt.com/api/v2/maps/{map_id}/elements/{element_id}",
  headers={"Authorization": f"Bearer {api_token}"},
)
assert r.ok
```

{% endtab %}

{% tab title="felt-python" %}

```python
from felt_python import delete_element

element_id = "<YOUR_ELEMENT_ID>"

delete_element(map_id, element_id)
```

{% endtab %}
{% endtabs %}
