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

# Schema Data & Stats

> Preview rows from schema tables, get field statistics, and upload CSV files for schema inference.

## POST /api/v1/schemas/{id}/data

Insert rows into a schema's underlying PostgreSQL table. Uses `ON CONFLICT DO NOTHING` to skip duplicate rows when a unique constraint exists.

### Path Parameters

| Parameter | Type   | Description |
| --------- | ------ | ----------- |
| `id`      | string | Schema ID   |

### Request Body

| Field  | Type      | Required | Description                                                                                                 |
| ------ | --------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `rows` | object\[] | Yes      | Array of row objects. Each key must match a column name in the schema. Between 1 and 5000 rows per request. |

### Example

```json theme={null}
{
  "rows": [
    { "customer_id": "C001", "full_name": "Alice Smith", "age": 30, "balance": 15000.50 },
    { "customer_id": "C002", "full_name": "Bob Jones", "age": 45, "balance": 82000.00 }
  ]
}
```

### Response -- `201 Created`

```json theme={null}
{
  "inserted": 2,
  "skipped": 0,
  "tableName": "ds_customers_abc123"
}
```

`inserted` is the number of rows **actually written** (from Postgres' affected-row
count), and `skipped` is the number dropped by `ON CONFLICT DO NOTHING` (duplicate
rows against a unique constraint). `inserted + skipped` equals the number of valid
rows submitted.

### Error Codes

| Code  | Reason                                                                                                                             |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Empty `rows` array, more than 5000 rows, per-table 5000-record limit exceeded, or the schema has no user-defined fields configured |
| `403` | The schema's backing table is outside the schema system (missing `ds_` prefix)                                                     |
| `404` | Schema not found                                                                                                                   |
| `429` | Rate limited (20 requests per 60 seconds)                                                                                          |
| `500` | Database insert failure                                                                                                            |

### Roles

admin, editor

***

## GET /api/v1/schemas/{id}/data

Preview rows from a schema's underlying PostgreSQL table. Only works for tables created by the schema system (tables with `ds_` prefix).

### Path Parameters

| Parameter | Type   | Description |
| --------- | ------ | ----------- |
| `id`      | string | Schema ID   |

### Query Parameters

| Parameter | Type    | Default | Description                |
| --------- | ------- | ------- | -------------------------- |
| `limit`   | integer | 50      | Max rows to return (1-500) |
| `offset`  | integer | 0       | Pagination offset          |

### Response

```json theme={null}
{
  "total": 5000,
  "limit": 50,
  "offset": 0,
  "rows": [
    {
      "id": 1,
      "customer_id": "CUST001",
      "age": 35,
      "credit_score": 740,
      "segment": "high_value"
    }
  ]
}
```

If the table does not exist yet (no data seeded), returns `{ "total": 0, "limit": <limit>, "offset": <offset>, "rows": [] }`.

### Roles

admin, editor, viewer

***

## GET /api/v1/schemas/{id}/stats

Returns per-field statistics for a schema's data. Results are cached for 5 minutes.

### Path Parameters

| Parameter | Type   | Description |
| --------- | ------ | ----------- |
| `id`      | string | Schema ID   |

### Response

```json theme={null}
{
  "fields": [
    {
      "name": "age",
      "type": "numeric",
      "min": 18,
      "max": 85,
      "avg": 42.3,
      "distinctCount": 68
    },
    {
      "name": "segment",
      "type": "text",
      "distinctCount": 4,
      "topValues": ["high_value", "medium_value", "low_value", "new"]
    }
  ],
  "totalRows": 5000,
  "cachedAt": "2026-03-30T12:00:00.000Z"
}
```

### Field Stat Types

**Numeric fields** include: `min`, `max`, `avg`, `distinctCount`

**Text fields** include: `distinctCount`, `topValues` (top 5 by frequency)

### Error Codes

| Code  | Reason                                                         |
| ----- | -------------------------------------------------------------- |
| `403` | Table name is not a schema-system table (missing `ds_` prefix) |
| `404` | Schema not found                                               |

### Roles

admin, editor, viewer

***

## POST /api/v1/schemas/upload

Upload a CSV file to infer column names and types. Does not create a schema or import data -- only analyzes the file structure. Useful for building schema creation forms from uploaded files.

### Request

Multipart form data with a single file field.

| Field  | Type | Required | Description         |
| ------ | ---- | -------- | ------------------- |
| `file` | File | Yes      | CSV file (max 50MB) |

### Limits

| Constraint    | Value                                                |
| ------------- | ---------------------------------------------------- |
| Max file size | 50 MB                                                |
| Allowed types | `text/csv`, `application/vnd.ms-excel`, `text/plain` |
| Sample size   | First 1 MB of file, up to 100 rows                   |

### Example

```bash theme={null}
curl -X POST https://playground.kaireonai.com/api/v1/schemas/upload \
  -H "X-Tenant-Id: my-tenant" \
  -F "file=@customers.csv"
```

### Response

```json theme={null}
{
  "columns": [
    { "name": "customer_id", "dataType": "varchar", "length": 50, "isNullable": true, "isPrimaryKey": false, "isUnique": false, "defaultValue": null },
    { "name": "age", "dataType": "integer", "isNullable": true, "isPrimaryKey": false, "isUnique": false, "defaultValue": null },
    { "name": "email", "dataType": "varchar", "length": 255, "isNullable": true, "isPrimaryKey": false, "isUnique": false, "defaultValue": null },
    { "name": "balance", "dataType": "numeric", "isNullable": true, "isPrimaryKey": false, "isUnique": false, "defaultValue": null }
  ],
  "rowCount": 100,
  "headers": ["customer_id", "age", "email", "balance"]
}
```

### Error Codes

| Code  | Reason                                             |
| ----- | -------------------------------------------------- |
| `400` | Missing file, no columns found, or CSV parse error |
| `413` | File exceeds 50 MB limit                           |
| `415` | Invalid file type (not CSV)                        |

### Roles

admin, editor

***

## Role Summary

| Endpoint              | Method | Allowed Roles         |
| --------------------- | ------ | --------------------- |
| `/schemas/{id}/data`  | POST   | admin, editor         |
| `/schemas/{id}/data`  | GET    | admin, editor, viewer |
| `/schemas/{id}/stats` | GET    | admin, editor, viewer |
| `/schemas/upload`     | POST   | admin, editor         |

See also: [Schemas](/api-reference/schemas) | [Data Platform](/data/overview)
