# Append rows over HTTP

[Read this page in HTML](https://www.scopedb.io/docs/api-reference/append)

Append writes rows directly to an existing table. Send one JSON object per line, with fields named after the table's columns. Use this path when your producer can supply the destination types; Append does not run a ScopeQL transformation or create missing tables.

For a continuous producer, use the append stream examples for [JavaScript](https://www.scopedb.io/docs/guides/sdks/nodejs.md#write-rows), [Go](https://www.scopedb.io/docs/guides/sdks/go.md#write-rows), or [Rust](https://www.scopedb.io/docs/guides/sdks/rust.md#write-rows) for batching and backpressure. The input types and delivery outcomes below also apply to those SDKs.

## Before you start

Set `SCOPEDB_ENDPOINT` and `SCOPEDB_API_KEY` using the [application connection guide](https://www.scopedb.io/docs/guides/connect-to-scopedb.md). Create the `events` table from the [quickstart](https://www.scopedb.io/docs/guides/quickstart.md#1-create-an-event-table) in the `scopedb` database and `public` schema. Its columns are `time`, `service`, `name`, `message`, and `var`.

If you use another table, [read its Catalog definition](https://www.scopedb.io/docs/api-reference/catalog.md#read-a-table-definition) and adapt the row before sending it.

## Send a batch

```http
POST /v1/catalog/databases/{database}/schemas/{schema}/tables/{table}/ingest
Content-Type: application/x-ndjson
Authorization: Bearer <api-key>
```

The request body is NDJSON itself, without a surrounding array or a `rows` wrapper. This example appends one event:

```bash
curl --fail-with-body --silent --show-error \
  "$SCOPEDB_ENDPOINT/v1/catalog/databases/scopedb/schemas/public/tables/events/ingest" \
  -H "Authorization: Bearer $SCOPEDB_API_KEY" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @- <<'NDJSON'
{"time":"2026-10-23T09:00:00Z","service":"checkout","name":"payment_failed","message":"Credit card gateway timed out","var":{"region":"apac","gateway":"credit_card"}}
NDJSON
```

A successful response is:

```json
{
  "status": "committed",
  "num_rows_inserted": 1
}
```

Each successful run appends another row. Append does not deduplicate repeated requests.

To send a file, replace the heredoc with `--data-binary @events.ndjson`. The endpoint accepts gzip-compressed bodies with `Content-Encoding: gzip`. Split larger inputs into batches: the HTTP endpoint limits uncompressed bodies to 16 MiB and NDJSON requests to 200,000 rows. The documented SDKs impose a smaller 8 MiB request cap; use that cap when preparing batches shared with an SDK.

## Verify the write

Submit this query through the [statement API](https://www.scopedb.io/docs/api-reference/statements.md#submit-a-statement) or Console:

```scopeql
FROM events
WHERE time = '2026-10-23T09:00:00Z'::timestamp
  AND service = 'checkout'
  AND name = 'payment_failed'
SELECT time, name, message, var['gateway']::string AS gateway
LIMIT 10
```

The row includes `payment_failed`, `Credit card gateway timed out`, and `credit_card`. A completed append is available to subsequent queries.

## JSON input types

Append validates the input against the destination schema. Convert fields in the producer before sending them. If the transformation needs ScopeQL, follow the separate [ingestion guide](https://www.scopedb.io/docs/guides/ingest-events.md).

| Column type | JSON input                                                                                                                                                                    |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `int`       | Integer number token in the signed 64-bit range, such as `42`. Quoted numbers, decimal tokens such as `42.0`, and exponent tokens such as `42e0` are rejected.                |
| `uint`      | Integer number token from zero through `9223372036854775807`. This input limit is narrower than the unsigned 64-bit query-result range.                                       |
| `float`     | Finite number. Integer tokens must be exactly representable as floats; overflow and nonzero values that underflow to zero are rejected.                                       |
| `boolean`   | JSON boolean, `true` or `false`.                                                                                                                                              |
| `string`    | JSON string; other types are not converted to text.                                                                                                                           |
| `timestamp` | RFC 3339 string with `T` and an explicit `Z` or `±HH:MM` offset, such as `"2026-10-23T09:00:00Z"`. Date-only strings, timezone-free strings, and numeric epochs are rejected. |
| `interval`  | Fixed-duration ISO 8601 string using hours, minutes, and seconds, such as `"PT1H2M3.000000004S"`. Calendar years, months, and days are not accepted.                          |
| `binary`    | Canonical padded standard Base64 string, such as `"aGVsbG8="`.                                                                                                                |
| `object`    | JSON object, not serialized JSON inside a string.                                                                                                                             |
| `array`     | JSON array; elements may have different types.                                                                                                                                |
| `any`       | Any JSON value, preserving its JSON kind. A timestamp-looking string stays a string.                                                                                          |

Timestamps and intervals must fit signed 64-bit nanoseconds, with up to nine fractional second digits. The signed 64-bit integer-token limit also applies inside structured values. Missing ordinary columns and explicit `null` become SQL NULL; nested nulls remain JSON nulls. Omit computed columns.

Unknown fields, duplicate object keys, and type mismatches reject the request. Other requests in a batch-producing application may already have committed.

## Delivery and retries

Check the HTTP status together with the delivery outcome. Success returns `status` at the top level; structured errors return it inside `details`.

| Outcome     | Meaning                         | Next action                                                                       |
| ----------- | ------------------------------- | --------------------------------------------------------------------------------- |
| `committed` | ScopeDB acknowledged the write. | Record `num_rows_inserted`; do not replay the batch.                              |
| `rejected`  | The request did not commit.     | Fix schema or input errors. Retry temporary availability rejections with backoff. |
| `unknown`   | The request may have committed. | Reconcile stored data before replaying; duplicates are possible.                  |

A schema failure returns HTTP `422` with a body such as:

```json
{
  "code": "invalid_schema",
  "message": "input does not match the table schema",
  "details": {
    "status": "rejected",
    "row_errors": [
      {"row_index": 0, "column": "time", "message": "invalid timestamp"}
    ],
    "row_errors_truncated": false
  }
}
```

The messages above are illustrative. Use `code` and `details.status` for decisions. `row_index` is zero-based within the request, `column` identifies the failing field, and `row_errors_truncated` tells you that more diagnostics were omitted. Fix the whole batch before resubmitting it.

A timeout, connection loss, or response without a trustworthy outcome must be treated as unknown after sending. An HTTP `503` alone cannot tell you whether the request was rejected or may have committed. Keep a durable copy of events when loss is unacceptable, and use stable event identifiers and application-level deduplication if you allow replay. See [HTTP errors and retries](https://www.scopedb.io/docs/api-reference.md#errors-and-retries).

## Related contents

* [API reference](https://www.scopedb.io/docs/api-reference.md)

* [Catalog over HTTP](https://www.scopedb.io/docs/api-reference/catalog.md)

* [SDKs](https://www.scopedb.io/docs/guides/sdks.md)
