Convert

Write an array of objects as CSV text

POST/v1/convert/json/to/csv

View as Markdown

Turns a JSON array of objects into CSV text with the columns, order and header labels you choose. Values with commas, quotes or line breaks are quoted correctly; the separator, the quoting policy (minimal or all), the line ending and a byte order mark for Excel are options. Objects and arrays inside a record are written as JSON in one cell, or flattened into columns like owner.name. Values written here read back unchanged through the parse operation.

Request body

Name Type Required Description
records array of object yes The rows, one object each
columns array of string no Columns to write and their order. Default: every key, in the order first seen
header_labels object no Header text per column name. Columns without a label keep their name
include_header boolean no False writes the data rows only (default true)
delimiter string no The one character between fields (default ",")
quoting one of: minimal, all no minimal or all (default "minimal")
line_ending one of: crlf, lf no crlf or lf (default "crlf")
byte_order_mark boolean no True starts the file with a byte order mark so Excel reads UTF-8 (default false)
nested one of: json, flatten no json or flatten (default "json")

Example request

A request body that works, as JSON.

{
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}

Code samples

Replace YOUR_TOKEN with your access token.

curl

curl -X POST 'https://api.skillfulsardine.com/v1/convert/json/to/csv' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}'

PowerShell

$body = @'
{
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}
'@
$response = Invoke-RestMethod -Method Post -Uri 'https://api.skillfulsardine.com/v1/convert/json/to/csv' `
  -Headers @{ Authorization = 'Bearer YOUR_TOKEN' } `
  -ContentType 'application/json; charset=utf-8' `
  -Body ([System.Text.Encoding]::UTF8.GetBytes($body))
$response | ConvertTo-Json -Depth 10

Python

import requests

payload = {
    "records": [
        {
            "name": "Ana",
            "city": "Porto",
            "note": "Likes coffee, black",
        },
        {
            "name": "João",
            "city": "Lisboa",
            "note": "",
        },
    ],
    "columns": [
        "name",
        "city",
        "note",
    ],
    "header_labels": {
        "name": "Name",
        "city": "City",
        "note": "Note",
    },
}

response = requests.post(
    "https://api.skillfulsardine.com/v1/convert/json/to/csv",
    headers={"Authorization": "Bearer YOUR_TOKEN"},
    json=payload,
    timeout=30,
)
print(response.json())

JavaScript

const response = await fetch("https://api.skillfulsardine.com/v1/convert/json/to/csv", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}),
});
const result = await response.json();
console.log(result);

Node

// Node 18 or later. Save as call.mjs and run: API_TOKEN=... node call.mjs
const token = process.env.API_TOKEN;

const response = await fetch("https://api.skillfulsardine.com/v1/convert/json/to/csv", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}),
});
const result = await response.json();
console.log(result);

Rust

// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let body: serde_json::Value = serde_json::from_str(r#"{
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}"#)?;
    let response = reqwest::blocking::Client::new()
        .post("https://api.skillfulsardine.com/v1/convert/json/to/csv")
        .bearer_auth("YOUR_TOKEN")
        .json(&body)
        .send()?;
    println!("{}", response.text()?);
    Ok(())
}

Swift

import Foundation

var request = URLRequest(url: URL(string: "https://api.skillfulsardine.com/v1/convert/json/to/csv")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(#"""
{
  "records": [
    {
      "name": "Ana",
      "city": "Porto",
      "note": "Likes coffee, black"
    },
    {
      "name": "João",
      "city": "Lisboa",
      "note": ""
    }
  ],
  "columns": [
    "name",
    "city",
    "note"
  ],
  "header_labels": {
    "name": "Name",
    "city": "City",
    "note": "Note"
  }
}
"""#.utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(decoding: data, as: UTF8.self))

Response

The fields inside data of a successful response.

Name Type Required Description
content string yes The CSV text
columns array of string yes Column names written, in order (before header labels)
row_count integer yes Number of data rows

Example response

A real answer from the operation, as JSON. The fields in the table above are inside data.

{
  "data": {
    "content": "Name,City,Note\r\nAna,Porto,\"Likes coffee, black\"\r\nJoão,Lisboa,\r\n",
    "columns": [
      "name",
      "city",
      "note"
    ],
    "row_count": 2
  },
  "errors": null,
  "meta": {
    "request_id": "fc5977a6-81bb-47ca-9343-ae362fa4e850",
    "timestamp": "2026-10-27T07:19:42.024838Z",
    "version": "2026-03-26"
  },
  "pagination": null
}

Responses

Status When it happens
200 Successful Response
400 The body respects the operation schema, but the use case rejected it. Each problem is one ApiError entry
413 The request is larger than the request size limit of the API allows
422 The body does not respect the operation schema. Each problem is one ApiError entry with the code validation_error
500 Something failed inside the server and was not an input problem. The same envelope, errors may be empty