---
seo_title: XML to CSV API for Converting Tabular XML to CSV | EnConvert
meta_desc: Convert XML to CSV via POST /v1/convert/xml-to-csv. Flattens tabular XML with repeated elements into comma-delimited rows, direct or via presigned URL.
keywords: xml to csv api, convert xml to csv, xml to csv converter api, xml to csv rest api, tabular xml to csv api, xml to csv python requests, xml to csv curl, export xml data to csv api
---

# XML to CSV API

The XML to CSV API converts a tabular XML file to CSV format with a single request to `POST /v1/convert/xml-to-csv`. It expects flat, repeated sibling elements with consistent child elements, and auto-unwraps `<root>` and `<item>` wrappers. The response is raw CSV by default, or set `direct_download=false` for metadata with a presigned download URL.

---

## Endpoint

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

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

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

**Output format:** `.csv` (`text/csv`)

---

## 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 `.xml` file to convert. Must contain tabular data (repeated elements with consistent fields). UTF-8 encoded. |
| `output_filename` | `string` | No | Input filename | Custom output filename. The `.csv` extension is added automatically. |
| `direct_download` | `boolean` | No | `true` | When `true`, returns raw CSV bytes. When `false`, returns metadata with a presigned download URL. |

---

## Conversion Rules

```xml
<root>
  <item>
    <name>Alice</name>
    <age>30</age>
    <city>London</city>
  </item>
  <item>
    <name>Bob</name>
    <age>25</age>
    <city>Paris</city>
  </item>
</root>
```

Becomes:

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

- Auto-unwraps `<root>` wrapper (single-key root dict)
- Auto-unwraps `<item>` wrapper (single-key dict containing the list)
- If a single XML record is found (not wrapped in a list), it is automatically wrapped in a list
- Column headers are derived from the first element's child tag names
- Delimiter is comma (not configurable), quoting is minimal

<div class="alert alert-warning">
<strong>Important:</strong> This endpoint only works with "tabular" XML -- flat, repeated sibling elements with consistent child elements. Deeply nested or mixed-content XML will fail or produce unexpected results. For complex XML structures, use <a href="/docs/endpoints/convert/data-formats/xml-to-json">xml-to-json</a> instead.
</div>

---

## Response

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

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

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

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

---

## Code Examples

### Python

```python
import requests

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

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

### Node.js

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

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

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

### PHP

```php
$ch = curl_init("https://api.enconvert.com/v1/convert/xml-to-csv");
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.xml", "application/xml")]
]);
$csv = curl_exec($ch);
curl_close($ch);
```

### Go

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

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/xml-to-csv", 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 `.xml` file |
| `400 Bad Request` | XML structure cannot be converted to CSV (not tabular) |
| `400 Bad Request` | XML must contain elements with consistent fields for CSV conversion |
| `400 Bad Request` | Invalid XML 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 |
| XML structure | Tabular (flat, repeated elements) only |
| Monthly conversions | Plan-dependent |

---

## Frequently asked questions

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

Send a `multipart/form-data` POST request to `POST /v1/convert/xml-to-csv` with your `.xml` 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 CSV bytes.

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

A `400 Bad Request` is returned when the XML structure is not tabular, the elements do not have consistent fields, the file is not a `.xml` file, or the encoding is not UTF-8.

### Can I convert deeply nested XML to CSV?

No. This endpoint only works with tabular XML, meaning flat, repeated sibling elements with consistent child elements. For complex or deeply nested XML structures, use the xml-to-json endpoint instead.

### How are CSV column headers determined from the XML?

Column headers are derived from the first element's child tag names. `<root>` and `<item>` wrappers are auto-unwrapped, and a single record is automatically wrapped in a list.

### Can I change the CSV delimiter in the output?

No. The delimiter is comma and is not configurable; quoting is minimal.
