---
seo_title: CSV to XML API for Converting CSV Files to XML | EnConvert
meta_desc: Convert CSV to XML via POST /v1/convert/csv-to-xml. Column headers become element tags, each row an item element. Direct download or presigned URL response.
keywords: csv to xml api, convert csv to xml, csv to xml converter api, csv to xml rest api, csv file to xml online api, csv to xml python requests, csv to xml curl, transform csv rows to xml api
---

# CSV to XML API

The CSV to XML API converts a CSV file to XML format with a single request to `POST /v1/convert/csv-to-xml`. Upload a UTF-8 `.csv` file via multipart form data. The first row's column headers become XML element tag names, and each subsequent row becomes an `<item>` element inside a `<root>` wrapper. The response is raw XML by default, or set `direct_download=false` for metadata with a presigned download URL.

---

## Endpoint

```
POST /v1/convert/csv-to-xml
```

**Content-Type:** `multipart/form-data`

**Accepted input:** `.csv` files (UTF-8 encoded)

**Output format:** `.xml` (`application/xml`)

---

## Authentication

Requires either a private API key or a JWT token from a public key.

```
X-API-Key: sk_your_private_key
```

Or:

```
Authorization: Bearer <jwt_token>
```

---

## Request Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `file` | file | Yes | -- | The `.csv` file to convert. First row must be column headers. UTF-8 encoded. |
| `output_filename` | `string` | No | Input filename | Custom output filename. The `.xml` extension is added automatically. |
| `direct_download` | `boolean` | No | `true` | When `true`, returns raw XML bytes. When `false`, returns metadata with a presigned download URL. |

---

## Conversion Rules

```csv
name,age,city
Alice,30,London
Bob,25,Paris
```

Becomes:

```xml
<?xml version="1.0" encoding="utf-8"?>
<root>
  <item>
    <name>Alice</name>
    <age>30</age>
    <city>London</city>
  </item>
  <item>
    <name>Bob</name>
    <age>25</age>
    <city>Paris</city>
  </item>
</root>
```

- First row is treated as column headers (used as XML element tag names)
- Each subsequent row becomes an `<item>` element
- Root element is always `<root>` (not configurable)
- Output is pretty-printed with 2-space indentation
- Delimiter is comma (not configurable)

---

## Response

### Direct Download (`direct_download=true`, default)

```
HTTP 200 OK
Content-Type: application/xml
Content-Disposition: inline; filename="data_20260405_123456789.xml"
```

### Metadata Response (`direct_download=false`)

```json
{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/csv-to-xml/data_20260405_123456789.xml",
    "filename": "data_20260405_123456789.xml",
    "file_size": 1234,
    "conversion_time_seconds": 0.03
}
```

---

## Code Examples

### Python

```python
import requests

with open("data.csv", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/csv-to-xml",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("data.csv", f, "text/csv")}
    )

with open("data.xml", "wb") as out:
    out.write(response.content)
```

### Node.js

```javascript
const form = new FormData();
form.append("file", fs.createReadStream("data.csv"));

const response = await fetch("https://api.enconvert.com/v1/convert/csv-to-xml", {
    method: "POST",
    headers: { "X-API-Key": "sk_your_private_key" },
    body: form
});

const xml = await response.text();
```

### PHP

```php
$ch = curl_init("https://api.enconvert.com/v1/convert/csv-to-xml");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["X-API-Key: sk_your_private_key"],
    CURLOPT_POSTFIELDS => ["file" => new CURLFile("data.csv", "text/csv")]
]);
$xml = curl_exec($ch);
curl_close($ch);
```

### Go

```go
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "data.csv")
file, _ := os.Open("data.csv")
io.Copy(part, file)
writer.Close()

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/csv-to-xml", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-Key", "sk_your_private_key")
resp, _ := http.DefaultClient.Do(req)
```

---

## Error Responses

| Status | Condition |
|--------|-----------|
| `400 Bad Request` | File is not a `.csv` file |
| `400 Bad Request` | CSV file is empty or has no valid rows |
| `400 Bad Request` | Invalid CSV encoding (expected UTF-8) |
| `401 Unauthorized` | Missing or invalid API key / JWT token |
| `402 Payment Required` | Monthly ops allowance exhausted |
| `413 Payload Too Large` | File exceeds plan's maximum file size |

---

## Limits

| Limit | Value |
|-------|-------|
| Max file size | Plan-dependent (Founding: 5 MB) |
| Input encoding | UTF-8 only |
| Monthly conversions | Plan-dependent |

---

## Frequently asked questions

### How do I convert CSV to XML with a REST API?

Send a `multipart/form-data` POST request to `POST /v1/convert/csv-to-xml` with your `.csv` file in the `file` field, authenticating with an `X-API-Key` header or a JWT `Authorization: Bearer` token. By default the response body is the raw XML bytes.

### How does the API map CSV columns and rows to XML elements?

The first CSV row is treated as column headers and used as XML element tag names. Each subsequent row becomes an `<item>` element inside a `<root>` wrapper, pretty-printed with 2-space indentation.

### Can I change the XML root element name or the CSV delimiter?

No. Neither value is configurable: the root element is always `<root>` and the delimiter is always a comma.

### Why does my CSV to XML conversion return a 400 error?

A `400 Bad Request` is returned when the upload is not a `.csv` file, the CSV is empty or has no valid rows, or the encoding is not UTF-8.

### Can I get a presigned download URL instead of the raw XML?

Yes. Set `direct_download=false` and the API returns JSON metadata including a `presigned_url`, `object_key`, `filename`, `file_size`, and `conversion_time_seconds`.
