# HTTP read task

> Learn how to acquire data from HTTP endpoints with Synnax.

This task follows the standard [task lifecycle](https://docs.synnaxlabs.com/reference/driver/task-basics#task-lifecycle).

## Task configuration reference

| Parameter   | Type   | Required | Default | Description                                                                                                                     |
| ----------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `device`    | string | Yes      | -       | Key of the HTTP server device                                                                                                   |
| `rate`      | number | No       | `1`     | Polling rate (Hz)                                                                                                               |
| `endpoints` | array  | Yes      | -       | List of [endpoint configurations](https://docs.synnaxlabs.com/reference/driver/http/read-task#endpoint-configuration-reference) |

## Endpoint configuration reference

Each endpoint defines an HTTP request to poll and a set of fields to extract from its JSON response.

| Parameter      | Type   | Required | Default | Description                                                                                                                   |
| -------------- | ------ | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `method`       | string | No       | `"GET"` | HTTP method                                                                                                                   |
| `path`         | string | Yes      | -       | URL path relative to the device base URL (e.g., `/api/v1/data`)                                                               |
| `headers`      | array  | No       | -       | Additional request headers as `{name, value}` pairs                                                                           |
| `query_params` | array  | No       | -       | Query parameters as `{parameter, value}` pairs                                                                                |
| `body`         | string | No       | -       | Request body (for POST or other methods that accept a body)                                                                   |
| `index`        | string | No       | -       | Key of the field whose channel indexes the others. Empty stamps samples on arrival                                            |
| `fields`       | array  | Yes      | -       | [Fields to extract](https://docs.synnaxlabs.com/reference/driver/http/read-task#field-extraction-reference) from the response |

## Field extraction reference

Fields define how to extract values from a JSON response body using [JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901) (RFC 6901). Each field maps a location in the response to a Synnax channel.

For example, given this response:

```json
{ "temperature": 23.5, "sensors": { "pressure": 101.3 } }
```

A pointer of `/temperature` extracts `23.5`, and `/sensors/pressure` extracts `101.3`.

| Parameter     | Type    | Required | Default     | Description                                                                                                                                             |
| ------------- | ------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pointer`     | string  | Yes      | -           | JSON Pointer path to the value (e.g., `/temperature`)                                                                                                   |
| `channel`     | number  | Yes      | -           | Synnax channel key to write the extracted value to                                                                                                      |
| `data_type`   | string  | No       | `"float64"` | Data type of the channel                                                                                                                                |
| `name`        | string  | No       | -           | Human-readable name for the field                                                                                                                       |
| `disabled`    | boolean | No       | `false`     | Excludes the field from polling                                                                                                                         |
| `time_format` | string  | No       | -           | [Timestamp format](https://docs.synnaxlabs.com/reference/driver/http/read-task#timestamp-handling) (required when the channel data type is `TIMESTAMP`) |
| `enum_values` | array   | No       | -           | String-to-number mapping for enum fields (e.g., `[{"label": "OFF", "value": 0}, {"label": "ON", "value": 1}]`)                                          |

Enum values

When the HTTP response contains string values that represent discrete states, use `enum_values` to map them to numbers. The Driver converts matching strings to their numeric equivalents before writing to the channel.

```python
http.ReadField(
    pointer="/status",
    channel=status_ch.key,
    data_type="float64",
    enum_values=[{"label": "OFF", "value": 0}, {"label": "ON", "value": 1}, {"label": "ERROR", "value": 2}],
)
```

If the response value does not match any key in the map, the Driver reports an error.

## Timestamp handling

By default, the Driver automatically generates timestamps for each poll cycle using software timing. If your HTTP response includes a timestamp field, you can extract it directly by setting `time_format` on a field whose channel data type is `TIMESTAMP`.

Supported timestamp formats

| Format     | Description                   | Example                      |
| ---------- | ----------------------------- | ---------------------------- |
| `iso8601`  | ISO 8601 date-time string     | `"2024-01-15T10:30:00.000Z"` |
| `unix_sec` | Seconds since Unix epoch      | `1705312200`                 |
| `unix_ms`  | Milliseconds since Unix epoch | `1705312200000`              |
| `unix_us`  | Microseconds since Unix epoch | `1705312200000000`           |
| `unix_ns`  | Nanoseconds since Unix epoch  | `1705312200000000000`        |

Software vs. hardware timing

**Software timing** (default): The Driver generates a timestamp at each poll cycle. All fields that share the same index channel are written atomically. No `time_format` is needed on any field.

**Hardware timing**: If your response includes a timestamp, create a `TIMESTAMP` channel as the index and add a field that extracts it with a `time_format`. Other fields using that index channel will be grouped with the extracted timestamp.

## How-to

**Console**

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/device-drivers/http/read-task/read-dark.mp4#t=0.001)

**Python**

Configure and run task

```python
import synnax as sy
from synnax import http

client = sy.Synnax()

# Retrieve the HTTP device
dev = client.devices.retrieve(name="My HTTP Server")

# Create an index channel for timestamps
http_time = client.channels.create(
    name="http_time",
    is_index=True,
    data_type=sy.DataType.TIMESTAMP,
    retrieve_if_name_exists=True,
)

# Create data channels
temperature = client.channels.create(
    name="http_temperature",
    index=http_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

pressure = client.channels.create(
    name="http_pressure",
    index=http_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

# Create the read task
task = http.ReadTask(
    name="HTTP Read Task",
    device=dev.key,
    rate=1,  # Poll at 1 Hz
    endpoints=[
        http.ReadEndpoint(
            method="GET",
            path="/api/v1/data",
            fields=[
                http.ReadField(
                    pointer="/temperature",
                    channel=temperature.key,
                    data_type="float64",
                    name="Temperature",
                ),
                http.ReadField(
                    pointer="/pressure",
                    channel=pressure.key,
                    data_type="float64",
                    name="Pressure",
                ),
            ],
        ),
    ],
)

# Configure the task with Synnax
client.tasks.configure(task)

# Start task and read data
with task.run():
    with client.open_streamer(
        ["http_temperature", "http_pressure"]
    ) as streamer:
        for _ in range(10):
            frame = streamer.read()
            print(frame)
```

Poll multiple endpoints

```python
import synnax as sy
from synnax import http

client = sy.Synnax()
dev = client.devices.retrieve(name="My HTTP Server")

http_time = client.channels.create(
    name="http_time",
    is_index=True,
    data_type=sy.DataType.TIMESTAMP,
    retrieve_if_name_exists=True,
)

temperature = client.channels.create(
    name="http_temperature",
    index=http_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

uptime = client.channels.create(
    name="http_uptime",
    index=http_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

task = http.ReadTask(
    name="Multi-Endpoint Read",
    device=dev.key,
    rate=1,
    endpoints=[
        http.ReadEndpoint(
            method="GET",
            path="/api/v1/data",
            fields=[
                http.ReadField(
                    pointer="/temperature",
                    channel=temperature.key,
                    data_type="float64",
                ),
            ],
        ),
        http.ReadEndpoint(
            method="GET",
            path="/api/v1/status",
            fields=[
                http.ReadField(
                    pointer="/uptime",
                    channel=uptime.key,
                    data_type="float64",
                ),
            ],
        ),
    ],
)

client.tasks.configure(task)
```

Use enum values

```python
import synnax as sy
from synnax import http

client = sy.Synnax()
dev = client.devices.retrieve(name="My HTTP Server")

http_time = client.channels.create(
    name="http_time",
    is_index=True,
    data_type=sy.DataType.TIMESTAMP,
    retrieve_if_name_exists=True,
)

power = client.channels.create(
    name="http_power",
    index=http_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

task = http.ReadTask(
    name="Enum Read",
    device=dev.key,
    rate=1,
    endpoints=[
        http.ReadEndpoint(
            method="GET",
            path="/api/v1/device",
            fields=[
                http.ReadField(
                    pointer="/power",
                    channel=power.key,
                    data_type="float64",
                    enum_values=[
                      {"label": "OFF", "value": 0},
                      {"label": "ON", "value": 1},
                    ],
                ),
            ],
        ),
    ],
)

client.tasks.configure(task)
```
