# HTTP write task

> Learn how to send commands to 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                                                                                                    |
| `endpoints` | array  | Yes      | -       | List of [endpoint configurations](https://docs.synnaxlabs.com/reference/driver/http/write-task#endpoint-configuration-reference) |

## Endpoint configuration reference

Each endpoint maps a single Synnax command channel to an HTTP request. When the channel receives a value, the Driver builds the JSON body and sends the request.

| Parameter      | Type    | Required | Default  | Description                                                                                                                 |
| -------------- | ------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `method`       | string  | No       | `"POST"` | HTTP method (`POST`, `PUT`, `PATCH`, or any method that accepts a body)                                                     |
| `path`         | string  | Yes      | -        | URL path relative to the device base URL (e.g., `/api/v1/setpoint`)                                                         |
| `headers`      | array   | No       | -        | Additional request headers as `{name, value}` pairs                                                                         |
| `query_params` | array   | No       | -        | Query parameters as `{parameter, value}` pairs                                                                              |
| `disabled`     | boolean | No       | `false`  | Excludes the endpoint from the task                                                                                         |
| `channel`      | object  | Yes      | -        | [Command channel field](https://docs.synnaxlabs.com/reference/driver/http/write-task#field-types-reference) configuration   |
| `fields`       | array   | No       | `[]`     | Additional [static or generated fields](https://docs.synnaxlabs.com/reference/driver/http/write-task#field-types-reference) |

## Field types reference

The request body is constructed from three types of fields, each placed at a JSON Pointer location in the body.

Channel field (required)

The channel field is the primary field on each endpoint. Its value comes from a Synnax command channel — when a value is written to the channel, the Driver places it in the request body at the specified pointer.

| Parameter     | Type   | Required | Default     | Description                                                                                                    |
| ------------- | ------ | -------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| `pointer`     | string | No       | `""`        | JSON Pointer where the value goes (e.g., `/value`). Empty sends the bare value as the body                     |
| `json_type`   | string | No       | `"number"`  | JSON type to serialize as: `number`, `string`, `boolean`                                                       |
| `channel`     | number | Yes      | -           | Synnax command channel key                                                                                     |
| `data_type`   | string | No       | `"float64"` | Data type of the channel                                                                                       |
| `time_format` | string | No       | -           | Timestamp format (only for `TIMESTAMP` data type): `iso8601`, `unix_sec`, `unix_ms`, `unix_us`, `unix_ns`      |
| `enum_values` | array  | No       | -           | String-to-number mapping for enum fields (e.g., `[{"label": "OFF", "value": 0}, {"label": "ON", "value": 1}]`) |

```python
http.ChannelField(
    pointer="/value",
    json_type="number",
    channel=setpoint_cmd.key,
)
```

Enum values

When the HTTP request body should contain 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.ChannelField(
    pointer="/source",
    json_type="string",
    channel=source_cmd.key,
    enum_values=[{"label": "OFF", "value": 0}, {"label": "ON", "value": 1}],
)
```

Static fields

Static fields place a fixed value in every request.

| Parameter   | Type   | Required | Default    | Description                                              |
| ----------- | ------ | -------- | ---------- | -------------------------------------------------------- |
| `pointer`   | string | No       | `""`       | JSON Pointer where the value goes (e.g., `/unit`)        |
| `json_type` | string | No       | `"number"` | JSON type to serialize as: `number`, `string`, `boolean` |
| `value`     | any    | Yes      | -          | Fixed JSON value placed at the pointer                   |

```python
http.StaticWriteField(
    pointer="/unit",
    json_type="string",
    value="psi",
)
```

Generated fields

Generated fields produce a new value for each request. Two generator types are supported:

| Parameter     | Type   | Required | Default     | Description                                                                                               |
| ------------- | ------ | -------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `pointer`     | string | Yes      | -           | JSON Pointer where the value goes (e.g., `/request_id`)                                                   |
| `generator`   | string | No       | `"uuid"`    | Generator type: `uuid` or `timestamp`                                                                     |
| `time_format` | string | No       | `"iso8601"` | Timestamp format (only for `timestamp` generator): `iso8601`, `unix_sec`, `unix_ms`, `unix_us`, `unix_ns` |

```python
# UUID generator - produces a unique ID per request
http.GeneratedWriteField(
    pointer="/request_id",
    generator="uuid",
)

# Timestamp generator - produces current time per request
http.GeneratedWriteField(
    pointer="/timestamp",
    generator="timestamp",
    time_format="iso8601",
)
```

## How-to

**Console**

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/device-drivers/http/write-task/write-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 a command time index
http_cmd_time = client.channels.create(
    name="http_cmd_time",
    is_index=True,
    data_type=sy.DataType.TIMESTAMP,
    retrieve_if_name_exists=True,
)

# Create a command channel
setpoint_cmd = client.channels.create(
    name="http_setpoint_cmd",
    index=http_cmd_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

# Create the write task
task = http.WriteTask(
    name="HTTP Write Task",
    device=dev.key,
    endpoints=[
        http.WriteEndpoint(
            method="PUT",
            path="/api/v1/setpoint",
            channel=http.ChannelField(
                pointer="/value",
                json_type="number",
                channel=setpoint_cmd.key,
            ),
        ),
    ],
)

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

# Start task and send commands
with task.run():
    with client.open_writer(
        start=sy.TimeStamp.now(),
        channels=[http_cmd_time.key, setpoint_cmd.key],
        enable_auto_commit=True,
    ) as writer:
        writer.write({
            http_cmd_time.key: sy.TimeStamp.now(),
            setpoint_cmd.key: 42.0,
        })
        writer.commit()
```

Use static and generated fields

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

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

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

setpoint_cmd = client.channels.create(
    name="http_setpoint_cmd",
    index=http_cmd_time.key,
    data_type=sy.DataType.FLOAT64,
    retrieve_if_name_exists=True,
)

# Each request body will contain:
# {
#   "value": <channel value>,
#   "source": "synnax",
#   "request_id": "<generated uuid>"
# }
task = http.WriteTask(
    name="HTTP Write Task",
    device=dev.key,
    endpoints=[
        http.WriteEndpoint(
            method="POST",
            path="/api/v1/control",
            channel=http.ChannelField(
                pointer="/value",
                json_type="number",
                channel=setpoint_cmd.key,
            ),
            fields=[
                http.StaticWriteField(
                    pointer="/source",
                    json_type="string",
                    value="synnax",
                ),
                http.GeneratedWriteField(
                    pointer="/request_id",
                    generator="uuid",
                ),
            ],
        ),
    ],
)

client.tasks.configure(task)
```
