# Nominal channel writer

Write data points to Nominal data sources.

OpenAPI file: [`NominalChannelWriterService.json`](https://dev.nominal.io/api/_downloads/963a21b18fed1a6d057a00ac0e400e2d/NominalChannelWriterService.json)

## Endpoints

### Write batches

POST `/storage/writer/v1`

Synchronously writes batches of records to a Nominal data source.

If the request is too large, either due to the number of individual batches (> 10) or the number of points across batches (> 500k), the request may be split up into multiple requests internally when writing to the Nominal data source. Generally, it’s advisable to limit the number of points to 50k.

Body

`batches` array of [`RecordsBatchExternal`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#recordsbatchexternal)
:   ​

    Fields of `RecordsBatchExternal`

    `channel` string required
    :   ​

    `tags` map of `TagName` to string
    :   ​

    `points` [`PointsExternal`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#pointsexternal) required
    :   ​

        **string**

        Set `type` to `"string"`.

        `string` array of [`StringPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#stringpoint)
        :   ​

            Fields of `StringPoint`

            `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
            :   ​

                Fields of `Timestamp`

                `seconds` integer (int64) required
                :   ​

                `nanos` integer (int64) required
                :   ​

            `value` string required
            :   ​

        **double**

        Set `type` to `"double"`.

        `double` array of [`DoublePoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#doublepoint)
        :   ​

            Fields of `DoublePoint`

            `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
            :   ​

            `value` number required
            :   ​

        **int**

        Set `type` to `"int"`.

        `int` array of [`IntPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#intpoint)
        :   ​

            Fields of `IntPoint`

            `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
            :   ​

            `value` integer required
            :   ​

        **uint64**

        Set `type` to `"uint64"`.

        `uint64` array of [`Uint64Point`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#uint64point)
        :   ​

            Fields of `Uint64Point`

            `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
            :   ​

            `value` integer (int64) required
            :   ​

        **array**

        Set `type` to `"array"`.

        `array` [`ArrayPoints`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#arraypoints)
        :   ​

            **double**

            Set `type` to `"double"`.

            `double` array of [`DoubleArrayPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#doublearraypoint)
            :   ​

                Fields of `DoubleArrayPoint`

                `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
                :   ​

                `value` array of number
                :   ​

            **string**

            Set `type` to `"string"`.

            `string` array of [`StringArrayPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#stringarraypoint)
            :   ​

                Fields of `StringArrayPoint`

                `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
                :   ​

                `value` array of string
                :   ​

        **struct**

        Set `type` to `"struct"`.

        `struct` array of [`StructPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#structpoint)
        :   ​

            Fields of `StructPoint`

            `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
            :   ​

            `jsonString` string required
            :   ​

    `unit` string
    :   ​

`dataSourceRid` string (RID) required
:   ​

`asynchronousInsert` boolean deprecated
:   Is always true - setting this to false will do nothing. **Deprecated:** Should not be used.

`sessionName` string
:   Optional client-provided session name identifier for tracing the origin of a write request.

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "dataSourceRid": "<nominal data source or dataset rid>"
}'
```

**requests**

```python
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1",
    headers={"Authorization": "Bearer <api key>"},
    json={"dataSourceRid": "<nominal data source or dataset rid>"},
)
response.raise_for_status()
```

**httpx**

```python
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1",
    headers={"Authorization": "Bearer <api key>"},
    json={"dataSourceRid": "<nominal data source or dataset rid>"},
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1",
            headers={"Authorization": "Bearer <api key>"},
            json={"dataSourceRid": "<nominal data source or dataset rid>"},
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Write column batches

POST `/storage/writer/v1/columnar`

Synchronously writes batches of columns of data to a Nominal data source.

This is a column-major variant of writeBatches (which is row-major) to optimize serialization and compression time for client applications streaming large numbers of points from a single column at a time. This has the tradeoff of slightly larger sizes post-gzipping of requests, so should be used in the particular case where the main bottleneck is in encoding columnar data into the row-based format found in writeBatches.

Body

`batches` array of [`ColumnBatch`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#columnbatch)
:   Batches of columnar data to stream to Nominal. Each channel’s data are provided as a column batch.

    Fields of `ColumnBatch`

    `channel` string required
    :   Channel within nominal to stream data to.

    `tags` map of `TagName` to string
    :   Mapping of key-value pairs to provide as tags to all points within the batch

    `timestamps` array of [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp)
    :   List of timestamp values that correspond to the provided list of column values. The number of timestamps provided MUST match the number of columnar values provided, otherwise a 400 error will be returned.

        Fields of `Timestamp`

        `seconds` integer (int64) required
        :   ​

        `nanos` integer (int64) required
        :   ​

    `values` [`ColumnValues`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#columnvalues) required
    :   List of time series values that should be ingested to a single channel. The number of columnar values provided MUST match the number of timestamps provided, otherwise a 400 error will be returned.

        **strings**

        Set `type` to `"strings"`.

        `strings` array of string
        :   ​

        **doubles**

        Set `type` to `"doubles"`.

        `doubles` array of number
        :   ​

        **ints**

        Set `type` to `"ints"`.

        `ints` array of integer
        :   ​

        **uint64s**

        Set `type` to `"uint64s"`.

        `uint64s` array of integer (int64)
        :   ​

        **arrays**

        Set `type` to `"arrays"`.

        `arrays` [`ArraysValues`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#arraysvalues)
        :   ​

            **strings1d**

            Set `type` to `"strings1d"`.

            `strings1d` array of array of string
            :   ​

            **doubles1d**

            Set `type` to `"doubles1d"`.

            `doubles1d` array of array of number
            :   ​

        **structs**

        Set `type` to `"structs"`.

        `structs` array of string
        :   ​

`dataSourceRid` string (RID) required
:   RID of the datasource (e.g., for a Connection) or dataset to stream data into.

`sessionName` string
:   Optional client-provided session name identifier for tracing the origin of a write request.

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/columnar" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "dataSourceRid": "<nominal data source or dataset rid>"
}'
```

**requests**

```python
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/columnar",
    headers={"Authorization": "Bearer <api key>"},
    json={"dataSourceRid": "<nominal data source or dataset rid>"},
)
response.raise_for_status()
```

**httpx**

```python
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/columnar",
    headers={"Authorization": "Bearer <api key>"},
    json={"dataSourceRid": "<nominal data source or dataset rid>"},
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/columnar",
            headers={"Authorization": "Bearer <api key>"},
            json={"dataSourceRid": "<nominal data source or dataset rid>"},
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Write Telegraf batches

POST `/storage/writer/v1/telegraf/{dataSourceRid}`

Synchronously writes batches of records to a Nominal data source.

Has the same functionality as writeBatches, but is compatible with the Telegraf output format. Assumes that the Telegraf batch format is used. Timestamp is assumed to be in nanoseconds. The URL in the Telegraf output plugin configuration should be the fully qualified URL, including the dataSourceRid query parameter.

Path parameters

`dataSourceRid` string (RID) required
:   ​

Body

`metrics` array of [`TelegrafMetric`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#telegrafmetric)
:   ​

    Fields of `TelegrafMetric`

    `fields` map of `Field` to any JSON value
    :   The values are expected to be either numeric or string values

    `name` string required
    :   The measurement name. Measurement name and field are concatenated when creating the Nominal channel name.

    `tags` map of `TagName` to string
    :   ​

    `timestamp` any JSON value required
    :   ​

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/telegraf/<data source rid>" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "metrics": [
    {
      "name": "<measurement name>",
      "timestamp": {}
    }
  ]
}'
```

**requests**

```python
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/telegraf/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
    json={"metrics": [{"name": "<measurement name>", "timestamp": {}}]},
)
response.raise_for_status()
```

**httpx**

```python
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/telegraf/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
    json={"metrics": [{"name": "<measurement name>", "timestamp": {}}]},
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/telegraf/<data source rid>",
            headers={"Authorization": "Bearer <api key>"},
            json={"metrics": [{"name": "<measurement name>", "timestamp": {}}]},
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Write Prometheus batches

POST `/storage/writer/v1/prometheus/{dataSourceRid}`

Synchronously writes batches of records to a Nominal data source.

Has the same functionality as writeBatches, but is encoded using the Prometheus remote write format. We follow the specification defined here: https://prometheus.io/docs/specs/remote_write_spec/ There are a few notable caveats: 1. Must be content encoded as application/x-protobuf 2. Must be compressed using snappy compression

Path parameters

`dataSourceRid` string (RID) required
:   ​

Body: `application/octet-stream`

The body is the raw bytes.

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@<file>"
```

**requests**

```python
from pathlib import Path

import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    data=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**httpx**

```python
from pathlib import Path

import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    content=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio
from pathlib import Path

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
            headers={
                "Authorization": "Bearer <api key>",
                "Content-Type": "application/octet-stream",
            },
            data=Path("<file>").read_bytes(),
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Prometheus remote write health check

GET `/storage/writer/v1/prometheus/{dataSourceRid}`

Performs a health check for prometheus remote write Vector sink. All this endpoint does is verify if the caller is authenticated and the server is online. Once Vector allows the Prometheus remote write endpoint to configure the healthcheck url, we can remove this endpoint.

See: https://github.com/vectordotdev/vector/issues/8279

Path parameters

`dataSourceRid` string (RID) required
:   ​

Response

The body is a boolean.

Request

**curl**

```shell
curl "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>" \
  -H "Authorization: Bearer <api key>"
```

**requests**

```python
import requests

response = requests.get(
    "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
```

**httpx**

```python
import httpx

response = httpx.get(
    "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
```

**aiohttp**

```python
import asyncio

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://api.gov.nominal.io/api/storage/writer/v1/prometheus/<data source rid>",
            headers={"Authorization": "Bearer <api key>"},
        ) as response:
            response.raise_for_status()
            print(await response.json())

asyncio.run(main())
```

Response: `200`

```json
true
```

### Write Nominal batches

POST `/storage/writer/v1/nominal/{dataSourceRid}`

Synchronously writes a Nominal Write Request to a Nominal data source using the NominalWrite Protobuf schema. The request must be Protobuf-encoded and accompanied by the appropriate content encoding headers if compressed.

The request should follow this Protobuf schema: ```proto message WriteRequestNominal { repeated Series series = 1; }

message Series { Channel channel = 1; map<string, string> tags = 2; // Key-value pairs for series tags Points points = 3; // Contains double, string, integer, array, or struct points }

message Channel { string name = 1; }

message Points { oneof points_type { DoublePoints double_points = 1; StringPoints string_points = 2; IntegerPoints integer_points = 3; ArrayPoints array_points = 4; StructPoints struct_points = 5; Uint64Points uint64_points = 6; } }

message DoublePoints { repeated DoublePoint points = 1; }

message StringPoints { repeated StringPoint points = 1; }

message IntegerPoints { repeated IntegerPoint points = 1; }

message Uint64Points { repeated Uint64Point points = 1; }

message ArrayPoints { oneof array_type { DoubleArrayPoints double_array_points = 1; StringArrayPoints string_array_points = 2; } }

message DoubleArrayPoints { repeated DoubleArrayPoint points = 1; }

message StringArrayPoints { repeated StringArrayPoint points = 1; }

message StructPoints { repeated StructPoint points = 1; }

message DoublePoint { google.protobuf.Timestamp timestamp = 1; double value = 2; }

message StringPoint { google.protobuf.Timestamp timestamp = 1; string value = 2; }

message IntegerPoint { google.protobuf.Timestamp timestamp = 1; int64 value = 2; }

message Uint64Point { google.protobuf.Timestamp timestamp = 1; uint64 value = 2; }

message DoubleArrayPoint { google.protobuf.Timestamp timestamp = 1; repeated double value = 2; }

message StringArrayPoint { google.protobuf.Timestamp timestamp = 1; repeated string value = 2; }

message StructPoint { google.protobuf.Timestamp timestamp = 1; string jsonString = 2; } ```

Each request can contain multiple series, where each series consists of: - A channel name - A map of tags (key-value pairs) - A collection of points, which can be double, string, integer, array (double/string), or struct (json) values - Each point includes a timestamp (using google.protobuf.Timestamp) and its value - Array points contain repeated values (array<double> or array<string>) - Struct points are represented using strings that contain the JSON formatted blobs, with all keys being strings

The endpoint requires the Content-Type header to be set to “application/x-protobuf”. If the payload is compressed, the appropriate Content-Encoding header must be included.

Path parameters

`dataSourceRid` string (RID) required
:   ​

Body: `application/octet-stream`

The body is the raw bytes.

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/nominal/<data source rid>" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@<file>"
```

**requests**

```python
from pathlib import Path

import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/nominal/<data source rid>",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    data=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**httpx**

```python
from pathlib import Path

import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/nominal/<data source rid>",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    content=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio
from pathlib import Path

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/nominal/<data source rid>",
            headers={
                "Authorization": "Bearer <api key>",
                "Content-Type": "application/octet-stream",
            },
            data=Path("<file>").read_bytes(),
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Write Nominal columnar batches

POST `/storage/writer/v1/nominal-columnar`

Synchronously writes to a Nominal data source using the columnar WriteBatchesRequest Protobuf schema.

This is the most efficient write format. Unlike the row-oriented writeNominalBatches endpoint, this schema stores timestamps and values as separate packed arrays per channel, which enables protobuf packed encoding for value arrays and significantly better compression.

The data_source_rid field in the protobuf body identifies the target data source or dataset. The request must be Protobuf-encoded and accompanied by the appropriate content encoding headers if compressed.

The request should follow this Protobuf schema: ```proto message WriteBatchesRequest { repeated RecordsBatch batches = 1; string data_source_rid = 2; }

message RecordsBatch { string channel = 1; map<string, string> tags = 2; Points points = 3; }

message Points { repeated Timestamp timestamps = 1; oneof points { DoublePoints double_points = 2; StringPoints string_points = 3; IntPoints int_points = 5; ArrayPoints array_points = 6; StructPoints struct_points = 7; Uint64Points uint64_points = 8; } }

// Nanosecond precision timestamp. message Timestamp { optional int64 seconds = 1; optional int64 nanos = 2; }

message DoublePoints { repeated double points = 1; } message StringPoints { repeated string points = 1; } message IntPoints { repeated int64 points = 1; } message Uint64Points { repeated uint64 points = 1; } message StructPoints { repeated string points = 1; }

message ArrayPoints { oneof array_type { DoubleArrayPoints double_array_points = 1; StringArrayPoints string_array_points = 2; } } message DoubleArrayPoints { repeated DoubleArrayPoint points = 1; } message DoubleArrayPoint { repeated double value = 2; } message StringArrayPoints { repeated StringArrayPoint points = 1; } message StringArrayPoint { repeated string value = 2; } ```

Body: `application/octet-stream`

The body is the raw bytes.

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/nominal-columnar" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@<file>"
```

**requests**

```python
from pathlib import Path

import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/nominal-columnar",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    data=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**httpx**

```python
from pathlib import Path

import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/nominal-columnar",
    headers={
        "Authorization": "Bearer <api key>",
        "Content-Type": "application/octet-stream",
    },
    content=Path("<file>").read_bytes(),
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio
from pathlib import Path

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/nominal-columnar",
            headers={
                "Authorization": "Bearer <api key>",
                "Content-Type": "application/octet-stream",
            },
            data=Path("<file>").read_bytes(),
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

### Write logs

POST `/storage/writer/v1/logs/{dataSourceRid}`

Synchronously writes logs to a Nominal data source.

Path parameters

`dataSourceRid` string (RID) required
:   ​

Body

`logs` array of [`LogPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#logpoint)
:   ​

    Fields of `LogPoint`

    `timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
    :   ​

        Fields of `Timestamp`

        `seconds` integer (int64) required
        :   ​

        `nanos` integer (int64) required
        :   ​

    `value` [`LogValue`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#logvalue) required
    :   ​

        Fields of `LogValue`

        `message` string required
        :   ​

        `args` map of string to string
        :   ​

`channel` string
:   If provided, the channel to which to write logs. If not provided, defaults to “logs”

Response

No content (HTTP 204).

Request

**curl**

```shell
curl -X POST "https://api.gov.nominal.io/api/storage/writer/v1/logs/<data source rid>" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "logs": [
    {
      "timestamp": {
        "seconds": 1,
        "nanos": 1
      },
      "value": {
        "message": "<message>"
      }
    }
  ],
  "channel": "<channel>"
}'
```

**requests**

```python
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/logs/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "logs": [
            {"timestamp": {"seconds": 1, "nanos": 1}, "value": {"message": "<message>"}},
        ],
        "channel": "<channel>",
    },
)
response.raise_for_status()
```

**httpx**

```python
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/storage/writer/v1/logs/<data source rid>",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "logs": [
            {"timestamp": {"seconds": 1, "nanos": 1}, "value": {"message": "<message>"}},
        ],
        "channel": "<channel>",
    },
)
response.raise_for_status()
```

**aiohttp**

```python
import asyncio

import aiohttp

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/storage/writer/v1/logs/<data source rid>",
            headers={"Authorization": "Bearer <api key>"},
            json={
                "logs": [
                    {
                        "timestamp": {"seconds": 1, "nanos": 1},
                        "value": {"message": "<message>"},
                    },
                ],
                "channel": "<channel>",
            },
        ) as response:
            response.raise_for_status()

asyncio.run(main())
```

Response: `204`

No content.

## Errors

[Errors](https://dev.nominal.io/api/legacy.md#errors) shows how these errors are sent.

Each error’s `errorName` is `NominalChannelWriter:` followed by its name below.

| Status | Name | Notes |
| --- | --- | --- |
| 400 | `ArrayTooLarge` | Array size exceeds maximum allowed length. |
| 400 | `ConflictingDataTypes` | Found two different data types for the same series in the request. |
| 400 | `ConflictingUnits` | Found two different units for the same channel in the request. |
| 400 | `DuplicateResolvedChannelName` | Multiple ingested columns resolve to the same channel name after applying channelPrefix and channelNameOverrides. Resolved channel names must be unique within a single ingest. |
| 400 | `InvalidChannelName` | The channel name is invalid. |
| 400 | `InvalidDataSource` | The nominal data source or dataset provided is invalid. |
| 400 | `InvalidStruct` | Ingested Struct is not a valid JSON struct |
| 400 | `InvalidTelegrafTimestamp` |  |
| 400 | `InvalidTimestamp` |  |
| 400 | `MismatchedTimestampsAndValues` | Columnar streaming request contains different numbers of timestamps and values |
| 400 | `ReservedTagName` | The request uses a tag name that is reserved for internal use. Remove the tag from the request. |
| 400 | `StreamingDisabledOnDataset` | Unsupported dataset for streaming. |
| 400 | `StreamingSessionRidNotAllowed` | The request sets a streaming session rid, which is assigned by Nominal and cannot be provided by the client. |
| 400 | `StructTooLarge` | Struct value exceeds maximum allowed UTF-8 byte size. |
| 400 | `TooManyChannelNameOverrides` | The request specifies more channel name overrides than the maximum allowed. |
| 400 | `TooManySessionSources` | The dataset has exceeded the maximum number of distinct active session sources allowed per hour. This is a best-effort limit enforced per channel-writer instance. |
| 413 | `PointsTooLarge` | The size of the points being written exceeds the maximum allowed size. |

## Types

### ArrayPoints

Array points for the internal API for directly writing points which supports all points types.

Set `type` to the name of one of the other fields, and set only that field.

`double` array of [`DoubleArrayPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#doublearraypoint)
:   ​

`string` array of [`StringArrayPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#stringarraypoint)
:   ​

### ArraysValues

Each element within the outer list corresponds to an Array point. Subsequent inner lists contain the array values recorded for that point.

Set `type` to the name of one of the other fields, and set only that field.

`strings1d` array of array of string
:   ​

`doubles1d` array of array of number
:   ​

### ColumnBatch

Batch of data to stream for a single channel with their associated timestamps.

`channel` string required
:   Channel within nominal to stream data to.

`tags` map of `TagName` to string
:   Mapping of key-value pairs to provide as tags to all points within the batch

`timestamps` array of [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp)
:   List of timestamp values that correspond to the provided list of column values. The number of timestamps provided MUST match the number of columnar values provided, otherwise a 400 error will be returned.

`values` [`ColumnValues`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#columnvalues) required
:   List of time series values that should be ingested to a single channel. The number of columnar values provided MUST match the number of timestamps provided, otherwise a 400 error will be returned.

### ColumnValues

List of values for a set of points to ingest from a single channel.

Set `type` to the name of one of the other fields, and set only that field.

`strings` array of string
:   ​

`doubles` array of number
:   ​

`ints` array of integer
:   ​

`uint64s` array of integer (int64)
:   ​

`arrays` [`ArraysValues`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#arraysvalues)
:   ​

`structs` array of string
:   ​

### DoubleArrayPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` array of number
:   ​

### DoublePoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` number required
:   ​

### IntPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` integer required
:   ​

### LogPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` [`LogValue`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#logvalue) required
:   ​

### LogValue

`message` string required
:   ​

`args` map of string to string
:   ​

### PointsExternal

Set `type` to the name of one of the other fields, and set only that field.

`string` array of [`StringPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#stringpoint)
:   ​

`double` array of [`DoublePoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#doublepoint)
:   ​

`int` array of [`IntPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#intpoint)
:   ​

`uint64` array of [`Uint64Point`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#uint64point)
:   ​

`array` [`ArrayPoints`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#arraypoints)
:   ​

`struct` array of [`StructPoint`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#structpoint)
:   ​

### RecordsBatchExternal

`channel` string required
:   ​

`tags` map of `TagName` to string
:   ​

`points` [`PointsExternal`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#pointsexternal) required
:   ​

`unit` string
:   ​

### StringArrayPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` array of string
:   ​

### StringPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` string required
:   ​

### StructPoint

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`jsonString` string required
:   ​

### TelegrafMetric

`fields` map of `Field` to any JSON value
:   The values are expected to be either numeric or string values

`name` string required
:   The measurement name. Measurement name and field are concatenated when creating the Nominal channel name.

`tags` map of `TagName` to string
:   ​

`timestamp` any JSON value required
:   ​

### Timestamp

Deprecated for new APIs. Use google.protobuf.Timestamp for absolute instants in proto APIs.

This legacy nanosecond precision timestamp type is represented by an epoch time in seconds and a nanosecond offset. The nanosecond offset is from the start of the epoch second, so must be less than 1 billion.

`seconds` integer (int64) required
:   ​

`nanos` integer (int64) required
:   ​

### Uint64Point

`timestamp` [`Timestamp`](https://dev.nominal.io/api/rest/nominal-channel-writer.md#timestamp) required
:   ​

`value` integer (int64) required
:   ​

Page design based on [Scalar](https://scalar.com), MIT License.
