---
title: "Upload a CSV or Excel file and preview the table it would create"
method: POST
path: "/table-imports/preview/"
tags: ["table-imports"]
---

# Upload a CSV or Excel file and preview the table it would create

`POST /table-imports/preview/`

## Request

- Base URL: `https://api.getoneprofile.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.getoneprofile.ai/table-imports/preview/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Upload a `.csv` or `.xlsx` file. The response carries one suggested column per field (a name taken from the header row and a type every sampled value fits) plus a few raw rows so the user can judge those guesses.

NOTHING is created here: no table, no columns, no rows. Review the mapping, edit it, and POST it to the commit endpoint to build the table.

The format is decided by the file's own first bytes, not by its name or its declared content type, both of which are client-supplied. A workbook is read one sheet at a time: `sheet_names` lists the rest and the sheet endpoint re-reads the same upload from another one.

Rejects a file that is too large or too wide, so an import that cannot succeed fails before it costs a table name. A file with more rows than the plan allows is NOT rejected: `importable_row_count` comes back below `estimated_row_count` and the import takes the file's first rows.

## Response `200`

Successful Response

- TableImportPreviewResponseSchema: What an upload returns: a mapping to review, and enough of the file to judge it. Nothing is created yet: no table, no columns, no rows. Edit the mapping and POST it to the commit endpoint to actually build the table. When `importable_row_count` is below `estimated_row_count` the file is longer than the plan allows and the import will take its first `importable_row_count` rows. Say so before the user commits: the two numbers are here as numbers, rather than as a sentence in `warnings`, because the client puts its upgrade control beside them.
  - `columns` ImportPreviewColumnSchema[], required: The inferred mapping.
    - `distribution` ValueDistribution, required
      - `distinct_count` integer, required
      - `empty_count` integer, required
      - `other_count` integer, required
      - `total_count` integer, required
      - `values` ValueFrequency[], required
        - `count` integer, required
        - `percentage` number, required
        - `value` string, required
    - `inferred_type` 'text' | 'paragraph' | 'url' | 'email' | 'image_url' | 'person' | 'select' | 'number' | 'decimal' | 'currency' | 'checkbox' | 'date' | 'multi_select' | 'list' | 'object', required: The type a user picks for a table column. Ordered as the picker shows them, which is also the order the groups below run in: text-ish, then numeric, then choice, then structured.
    - `name` string, required: Suggested column name, taken from the header row.
    - `sample_values` string[], required: A few raw values, to judge the guess by.
    - `source_index` integer, required: The field's zero-based position in the file.
  - `estimated_row_count` integer, required: Data rows in the file, excluding the header.
  - `import_id` string, uuid, required: Identifies this upload through commit and polling.
  - `importable_row_count` integer, required: How many of those rows the import will write, once the cap is applied.
  - `row_limit` integer, required: Rows one table may hold on this organisation's plan.
  - `sample_rows` array[], required: Raw sampled rows, in file order.
    - string[]
  - `selected_sheet` string, nullable: Which sheet these columns were read from. Null for a CSV. POST it to the sheet endpoint to re-read the same upload from a different one.
  - `sheet_names` string[]: Every sheet the uploaded workbook offers, in tab order. Empty for a CSV, which has no sheets. That is what says not to offer a sheet picker.
  - `warnings` string[], required: Non-fatal things the user should see.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `422`: Invalid request made to the API.
- `500`: Internal server error.
- `502`: Bad gateway error.
- `503`: Service unavailable.

---

[API](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile.md) · [All operations](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/llms.txt) · [OpenAPI document](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/revisions/4a6bd71e3f02?raw)
