Ingest GeoJSON Polygons Async | AgriBackup
Submit up to 5,000 GeoJSON farm-boundary polygons for satellite deforestation screening. Returns 202 Accepted with a jobId for async tracking.
import agribackup
from agribackup.rest import ApiException
# Initialize Client
configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
api_instance = agribackup.EnterprisePolygonsApi(api_client)
response = api_instance.ingest_polygons()
print(response)
except ApiException as e:
print("Exception when calling API: %s\n" % e)import { AgriBackupClient } from '@agribackup/sdk';
// Initialize Client
const client = new AgriBackupClient({
apiKey: 'sk_live_YOUR_API_KEY',
baseUrl: 'https://live.agribackup.com/api/v1'
});
async function execute() {
try {
const response = await client.polygons.ingestPolygons();
console.log(response);
} catch (error) {
console.error(error);
}
}import com.agribackup.client.*;
import com.agribackup.client.api.*;
import com.agribackup.client.model.*;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://live.agribackup.com/api/v1");
defaultClient.setApiKey("sk_live_YOUR_API_KEY");
EnterprisePolygonsApi apiInstance = new EnterprisePolygonsApi(defaultClient);
try {
Object result = apiInstance.ingestPolygons();
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling API: " + e.getResponseBody());
}
}
}using System;
using System.Threading.Tasks;
using AgriBackup.SDK.Api;
using AgriBackup.SDK.Client;
using AgriBackup.SDK.Model;
class Program {
static async Task Main() {
Configuration config = new Configuration();
config.BasePath = "https://live.agribackup.com/api/v1";
config.AddApiKey("ApiKeyAuth", "sk_live_YOUR_API_KEY");
var apiInstance = new EnterprisePolygonsApi(config);
try {
var result = await apiInstance.IngestPolygonsAsync();
Console.WriteLine(result);
} catch (ApiException e) {
Console.WriteLine("Exception when calling API: " + e.Message);
}
}
}curl --request POST \
--url https://live.agribackup.com/api/v1/enterprise/eudr/polygons \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
36.8,
-1.2
],
[
36.9,
-1.2
],
[
36.9,
-1.3
],
[
36.8,
-1.3
],
[
36.8,
-1.2
]
]
]
},
"properties": {
"farmer_name": "Global Coffee Farmer #1",
"farmer_id": "TEST_FARMER_100",
"plot_name": "Nyeri Hill Farm Block B",
"area": 2.5,
"unit": "HECTARES",
"commodity": "Coffee"
}
}
]
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
features: [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [[[36.8, -1.2], [36.9, -1.2], [36.9, -1.3], [36.8, -1.3], [36.8, -1.2]]]
},
properties: {
farmer_name: 'Global Coffee Farmer #1',
farmer_id: 'TEST_FARMER_100',
plot_name: 'Nyeri Hill Farm Block B',
area: 2.5,
unit: 'HECTARES',
commodity: 'Coffee'
}
}
]
})
};
fetch('https://live.agribackup.com/api/v1/enterprise/eudr/polygons', 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://live.agribackup.com/api/v1/enterprise/eudr/polygons",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'features' => [
[
'type' => 'Feature',
'geometry' => [
'type' => 'Polygon',
'coordinates' => [
[
[
36.8,
-1.2
],
[
36.9,
-1.2
],
[
36.9,
-1.3
],
[
36.8,
-1.3
],
[
36.8,
-1.2
]
]
]
],
'properties' => [
'farmer_name' => 'Global Coffee Farmer #1',
'farmer_id' => 'TEST_FARMER_100',
'plot_name' => 'Nyeri Hill Farm Block B',
'area' => 2.5,
'unit' => 'HECTARES',
'commodity' => 'Coffee'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-API-Key: <api-key>"
],
]);
$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://live.agribackup.com/api/v1/enterprise/eudr/polygons"
payload := strings.NewReader("{\n \"features\": [\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Polygon\",\n \"coordinates\": [\n [\n [\n 36.8,\n -1.2\n ],\n [\n 36.9,\n -1.2\n ],\n [\n 36.9,\n -1.3\n ],\n [\n 36.8,\n -1.3\n ],\n [\n 36.8,\n -1.2\n ]\n ]\n ]\n },\n \"properties\": {\n \"farmer_name\": \"Global Coffee Farmer #1\",\n \"farmer_id\": \"TEST_FARMER_100\",\n \"plot_name\": \"Nyeri Hill Farm Block B\",\n \"area\": 2.5,\n \"unit\": \"HECTARES\",\n \"commodity\": \"Coffee\"\n }\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://live.agribackup.com/api/v1/enterprise/eudr/polygons")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"features\": [\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Polygon\",\n \"coordinates\": [\n [\n [\n 36.8,\n -1.2\n ],\n [\n 36.9,\n -1.2\n ],\n [\n 36.9,\n -1.3\n ],\n [\n 36.8,\n -1.3\n ],\n [\n 36.8,\n -1.2\n ]\n ]\n ]\n },\n \"properties\": {\n \"farmer_name\": \"Global Coffee Farmer #1\",\n \"farmer_id\": \"TEST_FARMER_100\",\n \"plot_name\": \"Nyeri Hill Farm Block B\",\n \"area\": 2.5,\n \"unit\": \"HECTARES\",\n \"commodity\": \"Coffee\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"jobId": "job_998877",
"status": "PENDING",
"estimatedDurationSec": 3,
"createdAt": "2026-06-15T12:00:00Z"
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}202 Accepted immediately along with a jobId. Poll GET /api/v1/enterprise/eudr/jobs/{jobId} or listen for the polygon.verified webhook to confirm that verification has completed before referencing the polygon IDs in a batch.
Request Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | ✅ | Your live API key, e.g. sk_live_.... Generate one in the AgriBackup dashboard. |
Idempotency-Key | ✅ | A UUID v4 string. Replaying the same key within 24 hours returns the original response without re-queuing the job. |
X-Sub-Organization-ID | ☐ | Optional subsidiary identifier to scope polygon data to a specific business unit. |
Request Body
Send a JSON object with a singlefeatures array. Each element is a GeoJSON Feature with a Polygon geometry and a properties object describing the plot.
{
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[36.8, -1.2],
[36.9, -1.2],
[36.9, -1.3],
[36.8, -1.3],
[36.8, -1.2]
]
]
},
"properties": {
"farmer_name": "Global Coffee Farmer #1",
"farmer_id": "FARM-KE-001",
"plot_name": "Nyeri Hill Farm Block B",
"area": 2.5,
"unit": "HECTARES",
"commodity": "Coffee"
}
}
]
}
features array accepts 0–5,000 items per request. Exceeding 5,000 items returns 413 Payload Too Large.
Response — 202 Accepted
| Field | Type | Description |
|---|---|---|
jobId | string | Use this ID to poll job status via GET /api/v1/enterprise/eudr/jobs/{jobId}. |
status | string | Always PENDING on acceptance. |
estimatedDurationSec | integer | Estimated seconds until the verification pipeline completes. |
createdAt | string (ISO-8601) | Timestamp when the job was accepted. |
Location header pointing to the job status endpoint.
{
"jobId": "job_998877",
"status": "PENDING",
"estimatedDurationSec": 3,
"createdAt": "2026-06-15T12:00:00Z"
}
Async Completion — polygon.verified Webhook
When verification finishes, AgriBackup fires a polygon.verified event to your registered webhook URL. The payload is signed with X-AgriBackup-Signature (HMAC-SHA256). Polygons that pass screening receive eudrStatus: COMPLIANT and can immediately be referenced in batch registrations.
Code Examples
import agribackup
from agribackup.rest import ApiException
import uuid
configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
api_instance = agribackup.EnterprisePolygonsApi(api_client)
request = agribackup.PolygonIngestionRequest(
features=[
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[36.8, -1.2], [36.9, -1.2],
[36.9, -1.3], [36.8, -1.3], [36.8, -1.2]]
]
},
"properties": {
"farmer_id": "FARM-KE-001",
"commodity": "Coffee",
"area": 2.5,
"unit": "HECTARES"
}
}
]
)
response = api_instance.ingest_polygons(
idempotency_key=str(uuid.uuid4()),
polygon_ingestion_request=request
)
print("Job accepted:", response.job_id)
except ApiException as e:
print("Error:", e)
import { AgriBackupClient } from '@agribackup/sdk';
import { v4 as uuidv4 } from 'uuid';
const client = new AgriBackupClient({
apiKey: 'sk_live_YOUR_API_KEY',
baseUrl: 'https://live.agribackup.com/api/v1'
});
async function ingestPolygons() {
try {
const response = await client.polygons.ingestPolygons({
idempotencyKey: uuidv4(),
features: [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[[36.8, -1.2], [36.9, -1.2],
[36.9, -1.3], [36.8, -1.3], [36.8, -1.2]]
]
},
properties: {
farmerId: 'FARM-KE-001',
commodity: 'Coffee',
area: 2.5,
unit: 'HECTARES'
}
}
]
});
console.log('Job accepted:', response.jobId);
} catch (error) {
console.error('Error:', error.message);
}
}
curl -X POST https://live.agribackup.com/api/v1/enterprise/eudr/polygons \
-H "X-API-Key: sk_live_YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[36.8,-1.2],[36.9,-1.2],[36.9,-1.3],[36.8,-1.3],[36.8,-1.2]]
]
},
"properties": {
"farmer_id": "FARM-KE-001",
"commodity": "Coffee",
"area": 2.5,
"unit": "HECTARES"
}
}
]
}'
Authorizations
Enterprise API Key provided via the AgriBackup developer console.
Headers
Unique idempotency key (UUID) to prevent duplicate operations. Safely stored in Redis with a strict 24-hour TTL to prevent memory bloat during saturation attacks.
Optional identifier to partition compliance data (polygons, batches, declarations) for a specific subsidiary or regional business unit within the conglomerate.
Body
Payload to ingest GeoJSON polygons conforming to RFC 7946
Array of GeoJSON Features representing farm boundaries
5000Show child attributes
Show child attributes
Response
Polygon ingestion accepted and queued for verification
Response payload for asynchronously accepted jobs
The unique asynchronous tracking job ID
"job_998877"
Current execution status invariant
PENDING "PENDING"
Estimated duration in seconds before consensus or processing lock release
3
Timestamp when the job was accepted
"2026-06-15T12:00:00Z"
import agribackup
from agribackup.rest import ApiException
# Initialize Client
configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
api_instance = agribackup.EnterprisePolygonsApi(api_client)
response = api_instance.ingest_polygons()
print(response)
except ApiException as e:
print("Exception when calling API: %s\n" % e)import { AgriBackupClient } from '@agribackup/sdk';
// Initialize Client
const client = new AgriBackupClient({
apiKey: 'sk_live_YOUR_API_KEY',
baseUrl: 'https://live.agribackup.com/api/v1'
});
async function execute() {
try {
const response = await client.polygons.ingestPolygons();
console.log(response);
} catch (error) {
console.error(error);
}
}import com.agribackup.client.*;
import com.agribackup.client.api.*;
import com.agribackup.client.model.*;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://live.agribackup.com/api/v1");
defaultClient.setApiKey("sk_live_YOUR_API_KEY");
EnterprisePolygonsApi apiInstance = new EnterprisePolygonsApi(defaultClient);
try {
Object result = apiInstance.ingestPolygons();
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling API: " + e.getResponseBody());
}
}
}using System;
using System.Threading.Tasks;
using AgriBackup.SDK.Api;
using AgriBackup.SDK.Client;
using AgriBackup.SDK.Model;
class Program {
static async Task Main() {
Configuration config = new Configuration();
config.BasePath = "https://live.agribackup.com/api/v1";
config.AddApiKey("ApiKeyAuth", "sk_live_YOUR_API_KEY");
var apiInstance = new EnterprisePolygonsApi(config);
try {
var result = await apiInstance.IngestPolygonsAsync();
Console.WriteLine(result);
} catch (ApiException e) {
Console.WriteLine("Exception when calling API: " + e.Message);
}
}
}curl --request POST \
--url https://live.agribackup.com/api/v1/enterprise/eudr/polygons \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
36.8,
-1.2
],
[
36.9,
-1.2
],
[
36.9,
-1.3
],
[
36.8,
-1.3
],
[
36.8,
-1.2
]
]
]
},
"properties": {
"farmer_name": "Global Coffee Farmer #1",
"farmer_id": "TEST_FARMER_100",
"plot_name": "Nyeri Hill Farm Block B",
"area": 2.5,
"unit": "HECTARES",
"commodity": "Coffee"
}
}
]
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
features: [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [[[36.8, -1.2], [36.9, -1.2], [36.9, -1.3], [36.8, -1.3], [36.8, -1.2]]]
},
properties: {
farmer_name: 'Global Coffee Farmer #1',
farmer_id: 'TEST_FARMER_100',
plot_name: 'Nyeri Hill Farm Block B',
area: 2.5,
unit: 'HECTARES',
commodity: 'Coffee'
}
}
]
})
};
fetch('https://live.agribackup.com/api/v1/enterprise/eudr/polygons', 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://live.agribackup.com/api/v1/enterprise/eudr/polygons",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'features' => [
[
'type' => 'Feature',
'geometry' => [
'type' => 'Polygon',
'coordinates' => [
[
[
36.8,
-1.2
],
[
36.9,
-1.2
],
[
36.9,
-1.3
],
[
36.8,
-1.3
],
[
36.8,
-1.2
]
]
]
],
'properties' => [
'farmer_name' => 'Global Coffee Farmer #1',
'farmer_id' => 'TEST_FARMER_100',
'plot_name' => 'Nyeri Hill Farm Block B',
'area' => 2.5,
'unit' => 'HECTARES',
'commodity' => 'Coffee'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-API-Key: <api-key>"
],
]);
$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://live.agribackup.com/api/v1/enterprise/eudr/polygons"
payload := strings.NewReader("{\n \"features\": [\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Polygon\",\n \"coordinates\": [\n [\n [\n 36.8,\n -1.2\n ],\n [\n 36.9,\n -1.2\n ],\n [\n 36.9,\n -1.3\n ],\n [\n 36.8,\n -1.3\n ],\n [\n 36.8,\n -1.2\n ]\n ]\n ]\n },\n \"properties\": {\n \"farmer_name\": \"Global Coffee Farmer #1\",\n \"farmer_id\": \"TEST_FARMER_100\",\n \"plot_name\": \"Nyeri Hill Farm Block B\",\n \"area\": 2.5,\n \"unit\": \"HECTARES\",\n \"commodity\": \"Coffee\"\n }\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://live.agribackup.com/api/v1/enterprise/eudr/polygons")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"features\": [\n {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Polygon\",\n \"coordinates\": [\n [\n [\n 36.8,\n -1.2\n ],\n [\n 36.9,\n -1.2\n ],\n [\n 36.9,\n -1.3\n ],\n [\n 36.8,\n -1.3\n ],\n [\n 36.8,\n -1.2\n ]\n ]\n ]\n },\n \"properties\": {\n \"farmer_name\": \"Global Coffee Farmer #1\",\n \"farmer_id\": \"TEST_FARMER_100\",\n \"plot_name\": \"Nyeri Hill Farm Block B\",\n \"area\": 2.5,\n \"unit\": \"HECTARES\",\n \"commodity\": \"Coffee\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"jobId": "job_998877",
"status": "PENDING",
"estimatedDurationSec": 3,
"createdAt": "2026-06-15T12:00:00Z"
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}{
"code": "VALIDATION_FAILED",
"message": "Invalid polygon coordinates",
"details": [
{
"code": "INVALID_COORDINATE_CLOSURE",
"field": "features[0].properties.area",
"issue": "Area must be specified in hectares and cannot be negative"
}
]
}