Once your farm-boundary polygons pass satellite screening and carry a COMPLIANT status, you consolidate them into a batch that represents a single shipment unit of a regulated commodity. A batch ties together the commodity, origin country, HS code, quantity, and the verified polygon IDs that prove the land was not deforested. Registering a batch triggers an automated Copernicus risk assessment and anchors the result on the Hedera ledger. Like polygon ingestion, the endpoint returns 202 Accepted immediately and completes asynchronously.
Every batch requires at least one polygon ID with eudrStatus: COMPLIANT. If any polygon you include is still PENDING or is HIGH_RISK, the API returns a 400 Bad Request. Complete polygon ingestion first — see Polygon Ingestion.
Prerequisites
- One or more polygon IDs with
eudrStatus: COMPLIANT.
- The commodity’s HS code (6-digit minimum) and ISO 3-letter country-of-origin code.
- A
batch.risk_assessed webhook subscription to receive the completion event (see Webhooks Setup).
Step-by-step batch registration
Submit the batch registration request
Send a POST to /api/v1/enterprise/eudr/batches. Supply a UUID Idempotency-Key header to ensure the request is safe to retry.Required fields:| Field | Type | Description |
|---|
commodity | string | EUDR commodity name, e.g. "COFFEE" |
countryCode | string | ISO 3-letter origin code, e.g. "KEN" |
hsCode | string | HS code for dynamic validation, e.g. "090111" |
quantityKg | number | Total quantity in kilograms |
polygonIds | string[] | Array of COMPLIANT polygon IDs (max 5,000) |
Optional field:| Field | Type | Description |
|---|
vendorIds | string[] | ERP vendor IDs to map this batch to your Tier-1 supply chain |
import agribackup
from agribackup.rest import ApiException
import uuid
configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
batches_api = agribackup.EnterpriseBatchesApi(api_client)
job = batches_api.register_batch(
idempotency_key=str(uuid.uuid4()),
batch_registration_request={
"commodity": "COFFEE",
"countryCode": "KEN",
"hsCode": "090111",
"quantityKg": 5000.5,
"polygonIds": ["poly_abc123", "poly_def456"],
"vendorIds": ["ERP-VEND-991"]
}
)
print("Job accepted:", job.job_id)
print("Estimated duration (s):", job.estimated_duration_sec)
except ApiException as e:
print("Error:", e)
import { AgriBackupClient } from '@agribackup/sdk';
import { randomUUID } from 'crypto';
const client = new AgriBackupClient({ apiKey: 'sk_live_YOUR_API_KEY' });
async function registerBatch() {
try {
const job = await client.batches.register(
{
commodity: 'COFFEE',
countryCode: 'KEN',
hsCode: '090111',
quantityKg: 5000.5,
polygonIds: ['poly_abc123', 'poly_def456'],
vendorIds: ['ERP-VEND-991']
},
{ idempotencyKey: randomUUID() }
);
console.log('Job accepted:', job.jobId);
console.log('Estimated duration (s):', job.estimatedDurationSec);
} catch (error) {
console.error('Error:', error.message);
}
}
registerBatch();
curl --request POST \
--url https://live.agribackup.com/api/v1/enterprise/eudr/batches \
--header 'X-API-Key: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001' \
--data '{
"commodity": "COFFEE",
"countryCode": "KEN",
"hsCode": "090111",
"quantityKg": 5000.5,
"polygonIds": ["poly_abc123", "poly_def456"],
"vendorIds": ["ERP-VEND-991"]
}'
A successful 202 Accepted response:{
"jobId": "job_112233",
"status": "PENDING",
"estimatedDurationSec": 5,
"createdAt": "2026-07-08T09:00:00Z"
}
The Location header points to /api/v1/enterprise/eudr/jobs/job_112233 for polling. Retrieve the registered batch
Once the job completes, fetch the batch record with GET /api/v1/enterprise/eudr/batches/{batchId} to confirm its status and linked data.import agribackup
from agribackup.rest import ApiException
configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
batches_api = agribackup.EnterpriseBatchesApi(api_client)
batch = batches_api.get_batch(batch_id="uuid-1234")
print("Batch code:", batch.batch_code)
print("Status:", batch.status)
print("Risk state:", batch.consolidated_risk_state)
print("Linked polygons:", batch.polygon_ids)
except ApiException as e:
print("Error:", e)
import { AgriBackupClient } from '@agribackup/sdk';
const client = new AgriBackupClient({ apiKey: 'sk_live_YOUR_API_KEY' });
async function getBatch(batchId) {
try {
const batch = await client.batches.get(batchId);
console.log('Batch code:', batch.batchCode);
console.log('Status:', batch.status);
console.log('Risk state:', batch.consolidatedRiskState);
console.log('Linked polygons:', batch.polygonIds);
} catch (error) {
console.error('Error:', error.message);
}
}
getBatch('uuid-1234');
curl --request GET \
--url https://live.agribackup.com/api/v1/enterprise/eudr/batches/uuid-1234 \
--header 'X-API-Key: sk_live_YOUR_API_KEY'
The BatchDetailResponse schema:{
"batchId": "uuid-1234",
"batchCode": "COFFEE-KEN-20260612-ABCDEF",
"status": "CREATED",
"consolidatedRiskState": "COMPLIANT",
"polygonIds": ["poly_abc123", "poly_def456"],
"shipmentIds": []
}
Update a batch before anchoring
You may update a batch’s quantity, commodity description, HS code, or harvest date using PATCH /api/v1/enterprise/eudr/batches/{batchId}, provided it has not yet been anchored on-chain.import agribackup
from agribackup.rest import ApiException
configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
batches_api = agribackup.EnterpriseBatchesApi(api_client)
updated = batches_api.update_batch(
batch_id="uuid-1234",
batch_update_request={
"quantity": 4800.0,
"commodityDescription": "Green Coffee Beans — Washed",
"hsCode": "090111",
"harvestDate": "2026-07-15"
}
)
print("Updated batch:", updated)
except ApiException as e:
print("Error:", e)
import { AgriBackupClient } from '@agribackup/sdk';
const client = new AgriBackupClient({ apiKey: 'sk_live_YOUR_API_KEY' });
async function updateBatch(batchId) {
try {
const updated = await client.batches.update(batchId, {
quantity: 4800.0,
commodityDescription: 'Green Coffee Beans — Washed',
hsCode: '090111',
harvestDate: '2026-07-15'
});
console.log('Updated batch:', updated);
} catch (error) {
console.error('Error:', error.message);
}
}
updateBatch('uuid-1234');
curl --request PATCH \
--url https://live.agribackup.com/api/v1/enterprise/eudr/batches/uuid-1234 \
--header 'X-API-Key: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"quantity": 4800.0,
"commodityDescription": "Green Coffee Beans — Washed",
"hsCode": "090111",
"harvestDate": "2026-07-15"
}'
You cannot update a batch once its consolidatedRiskState has moved past PENDING_RISK_ASSESSMENT and it has been linked to a shipment. Attempting to do so returns 409 Conflict.
Delete a batch
To remove a batch that was created in error, send DELETE /api/v1/enterprise/eudr/batches/{batchId}. This permanently removes the record and cannot be undone. Batches that are already linked to a shipment must be unlinked first — see Logistics Linking.import agribackup
from agribackup.rest import ApiException
configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
batches_api = agribackup.EnterpriseBatchesApi(api_client)
batches_api.delete_batch(batch_id="uuid-1234")
print("Batch deleted.")
except ApiException as e:
print("Error:", e)
import { AgriBackupClient } from '@agribackup/sdk';
const client = new AgriBackupClient({ apiKey: 'sk_live_YOUR_API_KEY' });
async function deleteBatch(batchId) {
try {
await client.batches.delete(batchId);
console.log('Batch deleted.');
} catch (error) {
console.error('Error:', error.message);
}
}
deleteBatch('uuid-1234');
curl --request DELETE \
--url https://live.agribackup.com/api/v1/enterprise/eudr/batches/uuid-1234 \
--header 'X-API-Key: sk_live_YOUR_API_KEY'
A successful deletion returns 204 No Content.
Batch statuses
status / consolidatedRiskState | Meaning |
|---|
PENDING_RISK_ASSESSMENT | Copernicus risk check in progress |
COMPLIANT | All linked polygons passed; batch is clear for logistics |
HIGH_RISK | One or more polygons carry a deforestation signal |
LOW / MEDIUM / HIGH | Consolidated risk level from satellite analysis |
NONE | No risk detected across all linked polygons |
Use GET /api/v1/enterprise/eudr/batches with cursor-based pagination (starting_after parameter) to list all batches for your organization and filter by status.