Run a data feed transformation against a test input
Runs a Python transformation script against the data feed’s stored test input (or a file uploaded in the same request) and returns up to 3 preview rows. No events or runs are created. Real Python tracebacks are surfaced on failure, so callers can iterate write → test → save without the app’s testing console. The script in script_content is what runs; event_type_slug must name an event type with an active transformation on the data feed.
If a file is uploaded, it replaces the data feed’s stored test input. Otherwise the stored test input is used; if none exists, the request returns 422. Requires the read:data_feed token scope.
curl --request POST \
--url https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation \
--header 'Authorization: <api-key>' \
--header 'Content-Type: multipart/form-data' \
--form 'script_content=for row in rows:
events.append({'\''date'\'': row['\''Date'\''], '\''value'\'': float(row['\''Amount'\''])})' \
--form event_type_slug=combustion \
--form 'file=@example-file;type=text/csv'import requests
url = "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation"
files = { "file": ("example-file", open("example-file", "rb"), "text/csv") }
payload = {
"script_content": "for row in rows:
events.append({'date': row['Date'], 'value': float(row['Amount'])})",
"event_type_slug": "combustion"
}
headers = {"Authorization": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('script_content', 'for row in rows:
events.append({'date': row['Date'], 'value': float(row['Amount'])})');
form.append('event_type_slug', 'combustion');
form.append('file', '<string>');
const options = {method: 'POST', headers: {Authorization: '<api-key>'}};
options.body = form;
fetch('https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation")
.header("Authorization", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"events": [
{
"date": "2024-01-01",
"value": 100,
"unit": "tCO2e"
}
],
"test_input": {
"id": 42,
"filename": "emissions_2024.csv",
"content_type": "text/csv",
"file_size": 2048,
"uploaded_at": "2026-05-04T10:30:00Z"
}
}Authorizations
Path Parameters
The data feed's friendly ID (e.g. datafd_aBcD1234eFgH5678).
Body
The Python transformation script to execute
"for row in rows:\n events.append({'date': row['Date'], 'value': float(row['Amount'])})"
The slug of an event type with an active transformation on the data feed
"combustion"
Optional CSV or Excel file to use as the test input. Replaces the data feed's stored test input when provided. Max 50MB.
curl --request POST \
--url https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation \
--header 'Authorization: <api-key>' \
--header 'Content-Type: multipart/form-data' \
--form 'script_content=for row in rows:
events.append({'\''date'\'': row['\''Date'\''], '\''value'\'': float(row['\''Amount'\''])})' \
--form event_type_slug=combustion \
--form 'file=@example-file;type=text/csv'import requests
url = "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation"
files = { "file": ("example-file", open("example-file", "rb"), "text/csv") }
payload = {
"script_content": "for row in rows:
events.append({'date': row['Date'], 'value': float(row['Amount'])})",
"event_type_slug": "combustion"
}
headers = {"Authorization": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('script_content', 'for row in rows:
events.append({'date': row['Date'], 'value': float(row['Amount'])})');
form.append('event_type_slug', 'combustion');
form.append('file', '<string>');
const options = {method: 'POST', headers: {Authorization: '<api-key>'}};
options.body = form;
fetch('https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation")
.header("Authorization", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.gomangrove.com/api/v1/data_feeds/{data_feed_friendly_id}/test_transformation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"script_content\"\r\n\r\nfor row in rows:\r\n events.append({'date': row['Date'], 'value': float(row['Amount'])})\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"event_type_slug\"\r\n\r\ncombustion\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: text/csv\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"events": [
{
"date": "2024-01-01",
"value": 100,
"unit": "tCO2e"
}
],
"test_input": {
"id": 42,
"filename": "emissions_2024.csv",
"content_type": "text/csv",
"file_size": 2048,
"uploaded_at": "2026-05-04T10:30:00Z"
}
}