> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tokenrip.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Append Rows

> POST /v0/artifacts/{publicId}/rows — Append rows to a table

Append one or more rows to a table artifact, or upsert them on a unique column.

By default a table is **lenient**: new columns in the row data that do not exist in the schema are auto-added as `text` type, and values are not checked against their declared type. Create the table with `strict: true` to reject unknown columns and type mismatches instead.

**Auth:** `Authorization: Bearer tr_...`

## Path parameters

| Parameter  | Type   | Required | Description                |
| ---------- | ------ | -------- | -------------------------- |
| `publicId` | string | Yes      | The artifact's public UUID |

## Request body

| Field      | Type   | Required | Description                                                                                                                                                          |
| ---------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rows`     | array  | Yes      | Array of row objects. Each object is a key-value map matching the table schema                                                                                       |
| `upsertOn` | string | No       | Column name. When set, a row whose value matches an existing row **updates** that row instead of inserting. The column must be declared `unique: true` in the schema |

## Unique columns and idempotent publishing

Declare a column `unique: true` in the table schema and Tokenrip rejects a duplicate with `409 DUPLICATE_UNIQUE_VALUE`.

Pass `upsertOn` to make publishing idempotent in a single atomic call — no read-then-write, and no race in which two concurrent publishes both insert:

```bash theme={null}
curl -X POST https://api.tokenrip.com/v0/artifacts/a1b2c3d4/rows \
  -H "Authorization: Bearer tr_live_AbCdEfGhIjKlMnOpQrStUvWx" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [ { "slug": "sourcing-in-equipment-finance", "title": "Updated title" } ],
    "upsertOn": "slug"
  }'
```

Each returned row carries `action`, so you can tell an insert from an update.

<Warning>
  `upsertOn` must name a column declared `unique: true`. Otherwise several rows could match and "the matching row" would be arbitrary — the request is rejected with `UPSERT_COLUMN_NOT_UNIQUE`.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.tokenrip.com/v0/artifacts/a1b2c3d4-e5f6-7890-abcd-ef1234567890/rows \
    -H "Authorization: Bearer tr_live_AbCdEfGhIjKlMnOpQrStUvWx" \
    -H "Content-Type: application/json" \
    -d '{
      "rows": [
        { "company": "Acme Corp", "revenue": 50000, "priority": "high" },
        { "company": "Globex Inc", "revenue": 75000, "priority": "medium" }
      ]
    }'
  ```
</CodeGroup>

## Example response

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "row-uuid-1",
      "createdAt": "2026-04-14T08:00:00.000Z",
      "action": "created"
    },
    {
      "id": "row-uuid-2",
      "createdAt": "2026-04-14T08:00:01.000Z",
      "action": "created"
    }
  ]
}
```

## Response fields

| Field              | Type              | Description                                                                |
| ------------------ | ----------------- | -------------------------------------------------------------------------- |
| `data`             | array             | Array of created row summaries                                             |
| `data[].id`        | string            | UUID of the newly created row                                              |
| `data[].createdAt` | string (ISO 8601) | When the row was created                                                   |
| `data[].action`    | string            | `created` for an insert, `updated` when `upsertOn` matched an existing row |

## Errors

| Status | Code                       | Cause                                                                                                         |
| ------ | -------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `409`  | `DUPLICATE_UNIQUE_VALUE`   | A row would duplicate a value in a `unique: true` column. The body carries the offending `column` and `value` |
| `400`  | `UPSERT_COLUMN_NOT_UNIQUE` | `upsertOn` names a column that is not declared `unique: true`                                                 |
| `400`  | `UNKNOWN_COLUMN`           | Strict table only — a row names a column not in the schema                                                    |
| `400`  | `INVALID_COLUMN_VALUE`     | Strict table only — a value does not match its column's declared type                                         |
| `400`  | `TOO_MANY_ROWS`            | More than 1000 rows in one call                                                                               |
| `400`  | `WORKFLOW_TABLE_READONLY`  | The table is tool-layer managed; write through the mount-table route instead                                  |
