# CSV API
> A fast, fully-local CSV data toolkit: parse CSV into typed row objects (RFC-4180), compute per-column statistics (count, unique, type and top values, and for numeric columns min, max, mean, median and sum), remove duplicate rows by all or a subset of columns, sort by a column with numeric-aware ordering, and filter rows by a condition (equals, not-equals, greater/less than, contains, starts-with, empty, not-empty). Every endpoint accepts input via the query string or the request body, up to 2 MB, and returns both row objects and a CSV string. Pure server-side compute, no third-party upstream, so responses are instant and always available. Ideal for data wrangling, ETL, analytics preparation, spreadsheet tooling and data cleaning. (For plain CSV to JSON conversion, see the oanor JSON API.)

## Authentication
All requests require your oanor API key in the `x-oanor-key` header. Get one at https://www.oanor.com/developer/keys.

```bash
curl -H "x-oanor-key: oanor_live_…" "https://api.oanor.com/csv-api/..."
```

## Pricing
- **Free** (Free) — 11,000 calls/Mo, 2 req/s
- **Basic** ($4/Mo) — 190,000 calls/Mo, 8 req/s
- **Pro** ($15/Mo) — 1,100,000 calls/Mo, 25 req/s
- **Mega** ($38/Mo) — 5,500,000 calls/Mo, 80 req/s

## Endpoints

### CSV

#### `GET /v1/dedupe` — Remove duplicate rows

**Parameters:**
- `csv` (query, required, string) — CSV with header row Example: `name,age,city
Ada,36,Berlin
Bob,41,Paris`
- `columns` (query, optional, string) — Subset of columns to dedupe by Example: `name,city`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/csv-api/v1/dedupe?csv=name%2Cage%2Ccity%0AAda%2C36%2CBerlin%0ABob%2C41%2CParis&columns=name%2Ccity"
```

**Response:**
```json
{
    "data": {
        "csv": "name,age,city\nAda,36,Berlin\nBob,41,Paris",
        "rows": [
            {
                "age": 36,
                "city": "Berlin",
                "name": "Ada"
            },
            {
                "age": 41,
                "city": "Paris",
                "name": "Bob"
            }
        ],
        "count": 2,
        "columns": [
            "name",
            "age",
            "city"
        ],
        "removed": 0
    },
    "meta": {
        "timestamp": "2026-05-30T10:10:56.822Z",
        "request_id": "7d72f4cf-4ce0-4fa9-9779-0c8e960044b9"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/filter` — Filter rows

**Parameters:**
- `csv` (query, required, string) — CSV with header row Example: `name,age,city
Ada,36,Berlin
Bob,41,Paris`
- `column` (query, required, string) — Column Example: `age`
- `op` (query, optional, string) — eq, neq, gt, gte, lt, lte, contains, startswith, empty, notempty Example: `gte`
- `value` (query, optional, string) — Comparison value Example: `40`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/csv-api/v1/filter?csv=name%2Cage%2Ccity%0AAda%2C36%2CBerlin%0ABob%2C41%2CParis&column=age&op=gte&value=40"
```

**Response:**
```json
{
    "data": {
        "op": "gte",
        "csv": "name,age,city\nBob,41,Paris",
        "rows": [
            {
                "age": 41,
                "city": "Paris",
                "name": "Bob"
            }
        ],
        "count": 1,
        "value": "40",
        "column": "age",
        "columns": [
            "name",
            "age",
            "city"
        ]
    },
    "meta": {
        "timestamp": "2026-05-30T10:10:56.892Z",
        "request_id": "2e87b1af-ecce-463b-91a7-40fa3f722fbf"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/parse` — Parse CSV to rows

**Parameters:**
- `csv` (query, required, string) — CSV with header row Example: `name,age,city
Ada,36,Berlin
Bob,41,Paris`
- `delimiter` (query, optional, string) — Delimiter (default ,) Example: `,`
- `raw` (query, optional, string) — Keep all values as strings Example: `false`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/csv-api/v1/parse?csv=name%2Cage%2Ccity%0AAda%2C36%2CBerlin%0ABob%2C41%2CParis&delimiter=%2C&raw=false"
```

**Response:**
```json
{
    "data": {
        "rows": [
            {
                "age": 36,
                "city": "Berlin",
                "name": "Ada"
            },
            {
                "age": 41,
                "city": "Paris",
                "name": "Bob"
            }
        ],
        "count": 2,
        "columns": [
            "name",
            "age",
            "city"
        ]
    },
    "meta": {
        "timestamp": "2026-05-30T10:10:56.970Z",
        "request_id": "784f5822-6e2b-4299-97f4-c0f0d2113b28"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/sort` — Sort rows by column

**Parameters:**
- `csv` (query, required, string) — CSV with header row Example: `name,age,city
Ada,36,Berlin
Bob,41,Paris`
- `by` (query, required, string) — Column to sort by Example: `age`
- `order` (query, optional, string) — asc or desc Example: `desc`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/csv-api/v1/sort?csv=name%2Cage%2Ccity%0AAda%2C36%2CBerlin%0ABob%2C41%2CParis&by=age&order=desc"
```

**Response:**
```json
{
    "data": {
        "by": "age",
        "csv": "name,age,city\nBob,41,Paris\nAda,36,Berlin",
        "rows": [
            {
                "age": 41,
                "city": "Paris",
                "name": "Bob"
            },
            {
                "age": 36,
                "city": "Berlin",
                "name": "Ada"
            }
        ],
        "count": 2,
        "order": "desc",
        "columns": [
            "name",
            "age",
            "city"
        ]
    },
    "meta": {
        "timestamp": "2026-05-30T10:10:57.049Z",
        "request_id": "8479e8ef-4c67-4798-a96f-fc61e10768c1"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/stats` — Per-column statistics

**Parameters:**
- `csv` (query, required, string) — CSV with header row Example: `name,age,city
Ada,36,Berlin
Bob,41,Paris`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/csv-api/v1/stats?csv=name%2Cage%2Ccity%0AAda%2C36%2CBerlin%0ABob%2C41%2CParis"
```

**Response:**
```json
{
    "data": {
        "rows": 2,
        "stats": {
            "age": {
                "max": 41,
                "min": 36,
                "sum": 77,
                "mean": 38.5,
                "type": "number",
                "count": 2,
                "empty": 0,
                "median": 38.5,
                "unique": 2,
                "top_values": [
                    {
                        "count": 1,
                        "value": "36"
                    },
                    {
                        "count": 1,
                        "value": "41"
                    }
                ]
            },
            "city": {
                "type": "string",
                "count": 2,
                "empty": 0,
                "unique": 2,
                "top_values": [
                    {
                        "count": 1,
                        "value": "Berlin"
                    },
                    {
                        "count": 1,
                        "value": "Paris"
                    }
                ]
            },
            "name": {
                "type": "string",
                "count": 2,
                "empty": 0,
                "unique": 2,
                "top_values": [
                    {
                        "count": 1,
                        "value": "Ada"
                    },
                    {
                        "count": 1,
                        "value": "Bob"
                    }
…(truncated, see openapi.json for full schema)
```


---
Marketplace page: https://www.oanor.com/api/csv-api
OpenAPI spec: https://www.oanor.com/api/csv-api/openapi.json
