Skip to main content
This guide walks you through the complete EUDR compliance lifecycle from first API call to a filed Due Diligence Statement. By the end you will have submitted farm polygons for satellite verification, registered a consolidated commodity batch on the Hedera ledger, linked it to a Bill of Lading, and generated a TRACES NT–compliant DDS — all programmatically.
Run through this quickstart against the sandbox environment first. Use an API key prefixed with sk_test_ so no real Hedera transactions or TRACES NT submissions occur.

Prerequisites

  • An AgriBackup account with at least one API key. Generate keys from the developer console or via POST /api/v1/enterprise/api-keys.
  • One of the three supported runtimes: Python 3.9+, Node.js 18+, or Java 17+.

Step 1 — Install the SDK

pip install agribackup-sdk

Step 2 — Authenticate

Pass your API key once during client initialization. The SDK reads the sk_live_ or sk_test_ prefix and routes all requests to the correct base URL automatically — you never need to hard-code a host.
import agribackup

configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_test_YOUR_API_KEY'
Replace sk_test_YOUR_API_KEY with the key you generated from the dashboard.

Step 3 — Ingest farm polygons

Submit GeoJSON farm boundaries for satellite deforestation screening. This endpoint is asynchronous — it returns 202 Accepted with a jobId immediately. The actual Copernicus screening runs in the background; you receive a polygon.verified webhook (or can poll the job endpoint) when screening completes.
import agribackup
from agribackup.rest import ApiException

configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_test_YOUR_API_KEY'

with agribackup.ApiClient(configuration) as api_client:
    polygons_api = agribackup.EnterprisePolygonsApi(api_client)

    req = 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_name": "Global Coffee Farmer #1",
                    "farmer_id": "TEST_FARMER_100",
                    "plot_name": "Nyeri Hill Farm Block B",
                    "area": 2.5,
                    "unit": "HECTARES",
                    "commodity": "Coffee"
                }
            }
        ]
    )

    polygon_job = polygons_api.ingest_polygons(
        idempotency_key='tx_1001',
        polygon_ingestion_request=req
    )
    print("Polygon job accepted:", polygon_job.job_id)
Expected response (202 Accepted):
{
  "jobId": "job_998877",
  "status": "PENDING",
  "estimatedDurationSec": 3,
  "createdAt": "2026-06-15T12:00:00Z"
}
The Location response header also points directly to GET /api/v1/enterprise/eudr/jobs/job_998877 for polling. Wait for the polygon.verified webhook or poll until phase is COMPLETED before proceeding.

Step 4 — Register the consolidated batch

Once your polygons are verified, register a commodity batch that references the polygon IDs. AgriBackup cross-checks the polygon compliance state, triggers a Copernicus risk assessment, and anchors the batch on Hedera. This step is also asynchronous and returns 202 Accepted.
import agribackup
from agribackup.rest import ApiException

configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_test_YOUR_API_KEY'

with agribackup.ApiClient(configuration) as api_client:
    batches_api = agribackup.EnterpriseBatchesApi(api_client)

    batch = batches_api.register_batch(
        agribackup.BatchRegistration(
            batch_code='BR-2026-991',
            supplier_id='ERP-VEND-991',
            total_quantity=1500.0,
            unit='KGM',
            harvest_date='2026-07-08',
            valid_polygon_ids=[polygon_job.polygon_id]
        )
    )
    print("Batch registered:", batch.batch_id)
Expected response (202 Accepted):
{
  "jobId": "job_112233",
  "status": "PENDING",
  "estimatedDurationSec": 5,
  "createdAt": "2026-06-15T12:01:00Z"
}

Invoke the Hedera BATCH_SHIPMENT_GATEKEEPER smart contract to cryptographically lock the compliant batch to a logistics shipment. Provide the Bill of Lading number so it is permanently recorded on-chain. This emits a shipment.linked webhook on consensus.
import agribackup
from agribackup.rest import ApiException

configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_test_YOUR_API_KEY'

with agribackup.ApiClient(configuration) as api_client:
    logistics_api = agribackup.EnterpriseLogisticsApi(api_client)

    logistics_api.link_batch_to_shipment(
        agribackup.ShipmentLinkRequest(
            batch_id=batch.batch_id,
            shipment_reference='BOL-99281744'
        )
    )
    print("Shipment linked — awaiting consensus webhook")

Step 6 — Generate the Due Diligence Statement

Generate a TRACES NT–compliant DDS XML document. Provide SHA-256 hashes of your land tenure documents — AgriBackup anchors these hashes on Hedera as legal proof before generating the XML and filing it with TRACES NT.
import agribackup
from agribackup.rest import ApiException

configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_test_YOUR_API_KEY'

with agribackup.ApiClient(configuration) as api_client:
    try:
        declarations_api = agribackup.EnterpriseDeclarationsApi(api_client)

        dds = declarations_api.generate_dds(
            agribackup.DdsRequest(
                batch_id=batch.batch_id,
                operator_details={'name': 'Tier 1 Corp', 'country': 'KE'}
            )
        )
        print("DDS Successfully Filed. Reference:", dds.traces_nt_xml)

    except ApiException as e:
        print("Cryptographic Rejection:", e)
Expected response (202 Accepted):
{
  "jobId": "job_445566",
  "status": "PENDING",
  "estimatedDurationSec": 8,
  "createdAt": "2026-06-15T12:03:00Z"
}
When the DDS job completes, you receive a dds.submitted webhook containing the TRACES NT reference number and the Hedera consensus transaction ID.

The complete lifecycle at a glance

import agribackup
from agribackup.rest import ApiException

# 1. Initialize Cryptographic Authentication
# Base URL is automatically inferred from the API Key prefix (sk_live_ vs sk_test_)
configuration = agribackup.Configuration()
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'

with agribackup.ApiClient(configuration) as api_client:
    try:
        # 2. Ingest GeoJSON Polygons (Satellite Verification)
        polygons_api = agribackup.EnterprisePolygonsApi(api_client)
        polygon_job = polygons_api.ingest_polygons(idempotency_key='tx_1001', polygon_ingestion_request=req)

        # 3. Register the Consolidated Batch (Upon Oracle Compliance)
        batches_api = agribackup.EnterpriseBatchesApi(api_client)
        batch = batches_api.register_batch(agribackup.BatchRegistration(
            batch_code='BR-2026-991', supplier_id='ERP-VEND-991',
            total_quantity=1500.0, unit='KGM', harvest_date='2026-07-08',
            valid_polygon_ids=[polygon_job.polygon_id]
        ))

        # 4. Link Logistics (Bill of Lading)
        logistics_api = agribackup.EnterpriseLogisticsApi(api_client)
        logistics_api.link_batch_to_shipment(agribackup.ShipmentLinkRequest(
            batch_id=batch.batch_id, shipment_reference='BOL-99281744'
        ))

        # 5. Generate Due Diligence Statement (TRACES NT)
        declarations_api = agribackup.EnterpriseDeclarationsApi(api_client)
        dds = declarations_api.generate_dds(agribackup.DdsRequest(
            batch_id=batch.batch_id, operator_details={'name': 'Tier 1 Corp', 'country': 'KE'}
        ))

        print("DDS Successfully Filed. Reference:", dds.traces_nt_xml)

    except ApiException as e:
        print("Cryptographic Rejection:", e)
import { AgriBackupClient } from '@agribackup/sdk';

// 1. Initialize Cryptographic Authentication
// Base URL is automatically inferred from the API Key prefix
const client = new AgriBackupClient({
  apiKey: 'sk_live_YOUR_API_KEY'
});

async function executeComplianceLifecycle() {
  try {
    // 2. Ingest GeoJSON Polygons (Satellite Verification)
    const polygonJob = await client.polygons.ingestFromFile('./farm.geojson', {
      idempotencyKey: 'tx_uuid_1002'
    });

    // 3. Register the Consolidated Batch (Upon Oracle Compliance)
    const batch = await client.batches.ingest({
      batchCode: 'BR-2026-COCOA-991', supplierId: 'ERP-VEND-991',
      totalQuantity: 1500.0, unit: 'KGM', harvestDate: '2026-07-08',
      validPolygonIds: [polygonJob.polygonId]
    });

    // 4. Link Logistics (Bill of Lading)
    await client.logistics.linkBatchToShipment({
      batchId: batch.batchId, shipmentReference: 'BOL-99281744'
    });

    // 5. Generate Due Diligence Statement (TRACES NT)
    const dds = await client.declarations.generateDds({
      batchId: batch.batchId,
      operatorDetails: { name: 'Tier 1 Corp', country: 'KE' }
    });

    console.log('DDS Successfully Filed. Reference:', dds.tracesNtXml);

  } catch (e) {
    console.error("Cryptographic Rejection:", e.message);
  }
}
import com.agribackup.client.*;
import com.agribackup.client.api.*;
import com.agribackup.client.model.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;

public class ComplianceExecution {
    public static void main(String[] args) {
        // 1. Initialize Cryptographic Authentication
        // Base URL is automatically inferred from the API Key prefix
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setApiKey("sk_live_YOUR_API_KEY");

        try {
            // 2. Ingest GeoJSON Polygons (Satellite Verification)
            EnterprisePolygonsApi polygonsApi = new EnterprisePolygonsApi(defaultClient);
            JobAcceptedResponse polygonJob = polygonsApi.ingestPolygons(UUID.randomUUID(), req, null);

            // 3. Register the Consolidated Batch (Upon Oracle Compliance)
            EnterpriseBatchesApi batchesApi = new EnterpriseBatchesApi(defaultClient);
            BatchResponse batch = batchesApi.registerBatch(
                new BatchRegistration().batchCode("BR-2026-991").supplierId("ERP-VEND-991")
                .totalQuantity(new BigDecimal("1500.0")).unit("KGM").harvestDate(LocalDate.parse("2026-07-08"))
                .addValidPolygonIdsItem(polygonJob.getPolygonId())
            );

            // 4. Link Logistics (Bill of Lading)
            EnterpriseLogisticsApi logisticsApi = new EnterpriseLogisticsApi(defaultClient);
            logisticsApi.linkBatchToShipment(
                new ShipmentLinkRequest().batchId(batch.getBatchId()).shipmentReference("BOL-99281744")
            );

            // 5. Generate Due Diligence Statement (TRACES NT)
            EnterpriseDeclarationsApi declarationsApi = new EnterpriseDeclarationsApi(defaultClient);
            DeclarationResponse dds = declarationsApi.generateDds(
                new DdsRequest().batchId(batch.getBatchId())
                .operatorDetails(new OperatorDetails().name("Tier 1 Corp").country("KE"))
            );

            System.out.println("DDS Successfully Filed: " + dds.getTracesNtXml());

        } catch (ApiException e) {
            System.err.println("Cryptographic Rejection: " + e.getResponseBody());
        }
    }
}

Next steps

Authentication

Learn about live vs sandbox keys, base URL resolution, and securing your credentials.

Async Architecture

Understand the job and webhook model behind every 202 response.

Cryptographic Evidence

Retrieve and verify Hedera state proofs for auditors and customs authorities.

EUDR Compliance

Understand the regulation your integration must satisfy.