Skip to main content
Because satellite deforestation screening, Hedera DLT anchoring, and TRACES NT submission all take time, AgriBackup ingestion endpoints return a 202 Accepted response with a jobId rather than blocking until processing completes. You use this endpoint to poll that job and determine its current lifecycle phase, track how many records have been processed, inspect any structured errors, and retrieve the final cryptographic proofs once anchoring is complete. Your integration should poll this endpoint at a reasonable interval (we recommend every 2–5 seconds) until the phase field returns COMPLETED or FAILED, at which point you can also listen for the corresponding polygon.verified, shipment.linked, or job.failed webhook event.

Endpoint

GET /api/v1/enterprise/eudr/jobs/{jobId}

Path Parameters

jobId
string
required
The unique identifier of the asynchronous job to query. This value is returned in the jobId field of the 202 Accepted response from ingestion endpoints. Example: job_998877

Response Fields

jobId
string
required
The unique asynchronous tracking job ID. Example: job_998877
organizationId
string
required
The organization ID that initiated the job. Example: org_test_tier1_alpha
phase
string
required
The current execution phase of the job. Possible values: IMPORTING, ANALYZING, ANCHORING, GENERATING_CERTS, COMPLETED, FAILED.
totalRecords
integer
required
Total number of records (polygons, batches, etc.) submitted for this job.
processedRecords
integer
required
Number of records that have been processed so far. Use processedRecords / totalRecords to compute progress.
failedRecords
integer
required
Number of records that failed processing. A non-zero value does not necessarily mean the entire job failed — inspect the errors array for details.
compliantUnits
integer
required
Number of units (polygons or batches) that passed EUDR compliance checks. Present in the response once phase is COMPLETED.
highRiskUnits
integer
required
Number of units flagged as high-risk during satellite analysis. These require additional due diligence before DDS submission.
merkleRootHash
string
The Hedera Merkle root hash for the anchored dataset. Present once the ANCHORING phase is complete. Example: 0xabc123...
hederaTransactionId
string
The Hedera consensus transaction ID that provides immutable proof of anchoring. Example: 0.0.8713513@1713583200-000000000
startedAt
integer
required
Unix epoch millisecond timestamp of when the job began processing.
completedAt
integer
Unix epoch millisecond timestamp of when the job reached a terminal state (COMPLETED or FAILED). null if still in progress.
errors
object[]
required
A structured array of error objects for records that failed during this job. An empty array indicates no failures.
errors[].code
string
required
Programmatic error code for automated branch logic. Example: POLYGON_OVERLAP
errors[].field
string
The specific record identifier or field that caused the failure. Example: polygon_id_123
errors[].reason
string
required
Human-readable description of the failure. Example: Polygon 12 overlaps protected park space

Job Phase Lifecycle

IMPORTING → ANALYZING → ANCHORING → GENERATING_CERTS → COMPLETED
                                                      ↘ FAILED
PhaseDescription
IMPORTINGRecords are being ingested and validated
ANALYZINGCopernicus Sentinel-2 satellite deforestation analysis is running
ANCHORINGCompliance proofs are being anchored on Hedera Hashgraph
GENERATING_CERTSCryptographic compliance certificates are being generated
COMPLETEDAll records processed; hederaTransactionId is available
FAILEDJob terminated with errors; inspect the errors array

Error Responses

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid X-API-Key
403FORBIDDENYour API key does not have job monitoring permissions
404NOT_FOUNDNo job found for the provided jobId
import agribackup
from agribackup.rest import ApiException
import time

configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'

JOB_ID = "job_998877"
TERMINAL_PHASES = {"COMPLETED", "FAILED"}

with agribackup.ApiClient(configuration) as api_client:
    api_instance = agribackup.EnterpriseJobsApi(api_client)
    while True:
        try:
            job = api_instance.get_job_status(job_id=JOB_ID)
            print(f"Phase: {job.phase} | Processed: {job.processed_records}/{job.total_records}")

            if job.phase in TERMINAL_PHASES:
                if job.phase == "COMPLETED":
                    print(f"Job complete! Hedera TX: {job.hedera_transaction_id}")
                    print(f"Compliant: {job.compliant_units} | High Risk: {job.high_risk_units}")
                else:
                    print(f"Job failed with {len(job.errors)} error(s):")
                    for err in job.errors:
                        print(f"  [{err.code}] {err.field}: {err.reason}")
                break

            time.sleep(3)
        except ApiException as e:
            print("Exception when calling get_job_status: %s\n" % e)
            break
import { AgriBackupClient } from '@agribackup/sdk';

const client = new AgriBackupClient({
  apiKey: 'sk_live_YOUR_API_KEY',
  baseUrl: 'https://live.agribackup.com/api/v1'
});

async function pollJobStatus(jobId) {
  const terminalPhases = new Set(['COMPLETED', 'FAILED']);

  while (true) {
    try {
      const job = await client.jobs.getJobStatus({ jobId });
      console.log(`Phase: ${job.phase} | Processed: ${job.processedRecords}/${job.totalRecords}`);

      if (terminalPhases.has(job.phase)) {
        if (job.phase === 'COMPLETED') {
          console.log(`Job complete! Hedera TX: ${job.hederaTransactionId}`);
          console.log(`Compliant: ${job.compliantUnits} | High Risk: ${job.highRiskUnits}`);
        } else {
          console.log(`Job failed with ${job.errors.length} error(s):`);
          job.errors.forEach(err => {
            console.log(`  [${err.code}] ${err.field}: ${err.reason}`);
          });
        }
        break;
      }

      await new Promise(resolve => setTimeout(resolve, 3000));
    } catch (error) {
      console.error('Error polling job status:', error);
      break;
    }
  }
}

pollJobStatus('job_998877');
curl --request GET \
  --url https://live.agribackup.com/api/v1/enterprise/eudr/jobs/job_998877 \
  --header 'X-API-Key: sk_live_YOUR_API_KEY'

Example Response (Completed Job)

{
  "jobId": "job_998877",
  "organizationId": "org_test_tier1_alpha",
  "phase": "COMPLETED",
  "totalRecords": 10,
  "processedRecords": 10,
  "failedRecords": 0,
  "compliantUnits": 10,
  "highRiskUnits": 0,
  "merkleRootHash": "0xabc123def456...",
  "hederaTransactionId": "0.0.8713513@1713583200-000000000",
  "startedAt": 1713583200000,
  "completedAt": 1713583215000,
  "errors": []
}