> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agribackup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Register a Consolidated EUDR Batch Programmatically

> Group COMPLIANT polygon IDs into an EUDR batch, trigger a Copernicus risk assessment, and manage the batch lifecycle through update and delete operations.

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.

<Note>
  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](/guides/polygon-ingestion).
</Note>

## 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](/guides/webhooks-setup)).

## Step-by-step batch registration

<Steps>
  <Step title="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 |

    <CodeGroup>
      ```python Python theme={null}
      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)
      ```

      ```javascript Node.js theme={null}
      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();
      ```

      ```bash cURL theme={null}
      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"]
        }'
      ```
    </CodeGroup>

    A successful `202 Accepted` response:

    ```json theme={null}
    {
      "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.
  </Step>

  <Step title="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.

    <CodeGroup>
      ```python Python theme={null}
      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)
      ```

      ```javascript Node.js theme={null}
      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');
      ```

      ```bash cURL theme={null}
      curl --request GET \
        --url https://live.agribackup.com/api/v1/enterprise/eudr/batches/uuid-1234 \
        --header 'X-API-Key: sk_live_YOUR_API_KEY'
      ```
    </CodeGroup>

    The `BatchDetailResponse` schema:

    ```json theme={null}
    {
      "batchId": "uuid-1234",
      "batchCode": "COFFEE-KEN-20260612-ABCDEF",
      "status": "CREATED",
      "consolidatedRiskState": "COMPLIANT",
      "polygonIds": ["poly_abc123", "poly_def456"],
      "shipmentIds": []
    }
    ```
  </Step>

  <Step title="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.

    <CodeGroup>
      ```python Python theme={null}
      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)
      ```

      ```javascript Node.js theme={null}
      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');
      ```

      ```bash cURL theme={null}
      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"
        }'
      ```
    </CodeGroup>

    <Warning>
      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`.
    </Warning>
  </Step>

  <Step title="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](/guides/logistics-linking).

    <CodeGroup>
      ```python Python theme={null}
      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)
      ```

      ```javascript Node.js theme={null}
      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');
      ```

      ```bash cURL theme={null}
      curl --request DELETE \
        --url https://live.agribackup.com/api/v1/enterprise/eudr/batches/uuid-1234 \
        --header 'X-API-Key: sk_live_YOUR_API_KEY'
      ```
    </CodeGroup>

    A successful deletion returns `204 No Content`.
  </Step>
</Steps>

## 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              |

<Tip>
  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.
</Tip>
