DEV Community

Cover image for Building EUDR Compliance Made Simple: A Complete Guide to www.eudr-api.eu
Marko Frntić
Marko Frntić

Posted on

Building EUDR Compliance Made Simple: A Complete Guide to www.eudr-api.eu

What is EUDR and Why Should You Care?

The European Union Deforestation Regulation (EUDR) is a game-changing environmental law that came into effect in June 2023. It's designed to stop the import of products that contribute to deforestation and forest degradation worldwide. But here's the kicker: it affects any business that imports or exports certain commodities to/from the EU market.

🌍 The EUDR Impact

EUDR covers seven key commodities:

  • Timber and wood products
  • Coffee and cocoa
  • Soybeans and palm oil
  • Beef and leather
  • Rubber products

If your business deals with any of these products, you're now legally required to prove they're "deforestation-free" through comprehensive due diligence statements. Failure to comply can result in hefty fines, product seizures, and even market exclusion.

💡 How We're Solving the Problem

This is where www.eudr-api.eu comes in. We've built a production-ready, developer-friendly API that transforms the complex EUDR compliance process into simple REST endpoints. Instead of spending months building compliance systems from scratch, you can integrate our API in days and start submitting due diligence statements immediately.

Our platform handles:

  • Automated validation of EUDR requirements
  • Standardized data formats for all compliance documents
  • Real-time submission to EU authorities
  • Comprehensive tracking and amendment capabilities
  • Developer-friendly REST API with clear documentation

Who This Guide Is For

This comprehensive guide is designed for:

  • Developers building compliance applications
  • Business analysts implementing EUDR workflows
  • Compliance officers looking for technical solutions
  • Product managers planning EUDR integration
  • Anyone who needs to understand EUDR compliance from a technical perspective

What You'll Learn

By the end of this guide, you'll be able to:

  1. Understand EUDR compliance requirements and how our API addresses them
  2. Integrate all EUDR services into your applications
  3. Handle the complete compliance workflow from submission to amendment
  4. Implement proper error handling and validation
  5. Build production-ready EUDR compliance systems

🚀 Quick Start Guide

Prerequisites

Before you can use our API, you need:

  1. EUDR Web Service credentials from the EUDR Traces system
  2. API key from www.eudr-api.eu

Step 1: Get Your API Key

  1. Register for a free account at www.eudr-api.eu
  2. Verify your email address to activate your account
  3. Complete your profile setup to access the API
  4. Go to your API Keys Dashboard
  5. Create a new API key for either Test (Acceptance) environment
  6. Copy your API key - you'll need it for all requests

Step 2: Choose API Version

The API supports two versions with different DDS submission formats:

  • Version 1: Legacy EUDR compliance
  • Version 2: Latest EUDR standards (default and recommended)

Version Header (Optional):

x-api-eudr-version: 2
Enter fullscreen mode Exit fullscreen mode

If no version header is provided, Version 2 is automatically selected.

Step 3: Make Your First API Call

Test your setup with the Echo Service - a simple connectivity verification endpoint:

Echo Service Endpoint:

GET /api/eudr/echo?message=Hello EUDR API
Enter fullscreen mode Exit fullscreen mode

Complete Request Examples:

cURL:

curl -X GET "https://www.eudr-api.eu/api/eudr/echo?message=Hello EUDR API" \
  -H "x-api-key: YOUR_API_KEY_HERE" \
  -H "x-api-eudr-version: 2"
Enter fullscreen mode Exit fullscreen mode

JavaScript:

const response = await fetch('/api/eudr/echo?message=Hello EUDR API', {
  method: 'GET',
  headers: {
    'x-api-key': 'YOUR_API_KEY_HERE',
    'x-api-eudr-version': '2'
  }
});

const data = await response.json();
console.log(data);
Enter fullscreen mode Exit fullscreen mode

Python:

import requests

url = "https://www.eudr-api.eu/api/eudr/echo"
params = {"message": "Hello EUDR API"}
headers = {
    "x-api-key": "YOUR_API_KEY_HERE",
    "x-api-eudr-version": "2"
}

response = requests.get(url, params=params, headers=headers)
data = response.json()
print(data)
Enter fullscreen mode Exit fullscreen mode

R:

library(httr)

url <- "https://www.eudr-api.eu/api/eudr/echo"
query <- list(message = "Hello EUDR API")
headers <- add_headers(
  "x-api-key" = "YOUR_API_KEY_HERE",
  "x-api-eudr-version" = "2"
)

response <- GET(url, query = query, headers)
data <- content(response, "parsed")
print(data)
Enter fullscreen mode Exit fullscreen mode

.NET:

using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text.Json;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY_HERE");
client.DefaultRequestHeaders.Add("x-api-eudr-version", "2");

var response = await client.GetAsync("https://www.eudr-api.eu/api/eudr/echo?message=Hello EUDR API");
var content = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<dynamic>(content);
Console.WriteLine(data);
Enter fullscreen mode Exit fullscreen mode

API Overview

Base Configuration

  • Base URL: https://www.eudr-api.eu/api
  • EUDR base path: /eudr
  • API versions: 1 and 2 (defaults to 2 if not specified)
  • Authentication: API key required via x-api-key header

Required Headers

x-api-key: <YOUR_API_KEY>
x-api-eudr-version: 2  # Optional, defaults to '2'
Content-Type: application/json  # For POST/PUT/DELETE requests
Enter fullscreen mode Exit fullscreen mode

Response Format

All endpoints return responses in this consistent format:

{
  "status": "success|error",
  "httpStatus": 200|201|400|401|500,
  "data": { /* response data */ },
  "message": "Error message if applicable",
  "code": "ERROR_CODE if applicable",
  "details": { /* additional error details */ }
}
Enter fullscreen mode Exit fullscreen mode

Authentication Headers Reference

Header Description Example Required
x-api-key Your API authentication key eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ✅ Required
x-api-eudr-version API version (1 or 2) 2 ⚠️ Optional
Authorization Alternative auth method (legacy) Bearer YOUR_API_KEY ⚠️ Optional

Response Codes

Code Status Description
200 Success Request completed successfully
201 Created Resource created successfully
400 Bad Request Invalid request parameters
401 Unauthorized Missing or invalid API key
403 Forbidden EUDR credentials not configured
408 Request Timeout Timestamp window expired
500 Server Error Internal server error

1. Echo Service - Connectivity Testing

Purpose: Test API connectivity and verify credentials

Endpoints:

  • GET /eudr/echo - Query parameter based
  • POST /eudr/echo - Body parameter based

Validation Rules:

  • message parameter is required
  • For GET: ?message=<string>
  • For POST: {"message": "<string>"}

Request Examples:

GET:

curl -X GET \
  -H "x-api-key: YOUR_API_KEY" \
  "https://www.eudr-api.eu/api/eudr/echo?message=ping"
Enter fullscreen mode Exit fullscreen mode

POST:

curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"ping"}' \
  "https://www.eudr-api.eu/api/eudr/echo"
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "success",
  "httpStatus": 200,
  "data": {
    "message": "ping"
  }
}
Enter fullscreen mode Exit fullscreen mode

Error Response (400):

{
  "status": "error",
  "httpStatus": 400,
  "message": "Message is required"
}
Enter fullscreen mode Exit fullscreen mode

2. DDS Submission Service

Purpose: Create new Due Diligence Statement (DDS) submissions

Endpoint: POST /eudr/dds

Validation Rules:

  • Request body must not be empty
  • Full DDS statement data required
  • API version affects validation schema

Request Example:

{
  "operatorType": "OPERATOR",
  "statement": {
    "internalReferenceNumber": "HR-000002",
    "activityType": "DOMESTIC",
    "borderCrossCountry": "FR",
    "comment": "Test submission",
    "commodities": [
      {
        "position": 1,
        "descriptors": {
          "descriptionOfGoods": "Timber products",
          "goodsMeasure": {
            "volume": 20,
            "netWeight": 40,
            "supplementaryUnit": 10,
            "supplementaryUnitQualifier": "MTQ"
          }
        },
        "hsHeading": "4401",
        "speciesInfo": {
          "scientificName": "Carpinus betulus",
          "commonName": "Hornbeam"
        },
        "producers": [
          {
            "country": "FR",
            "name": "Producer 1",
            "geometryGeojson": "<BASE64_ENCODED_GEOJSON>"
          }
        ]
      }
    ],
    "geoLocationConfidential": false
  }
}
Enter fullscreen mode Exit fullscreen mode

Response (201):

{
  "status": "success",
  "httpStatus": 201,
  "data": {
    "ddsIdentifier": "UUID-12345-67890"
  }
}
Enter fullscreen mode Exit fullscreen mode

Error Response (400):

{
  "status": "error",
  "httpStatus": 400,
  "message": "DDS statement data is required"
}
Enter fullscreen mode Exit fullscreen mode

3. DDS Retrieval Services

3.1 Get DDS Info by UUIDs

Purpose: Retrieve DDS information using UUID identifiers

Endpoints:

  • GET /eudr/dds/info?uuids=UUID1,UUID2,UUID3
  • POST /eudr/dds/info

Validation Rules:

  • GET: uuids as comma-separated string
  • POST: uuids as array in request body
  • At least one UUID required
  • All UUIDs must be strings

Request Examples:

GET:

curl -X GET \
  -H "x-api-key: YOUR_API_KEY" \
  "https://www.eudr-api.eu/api/eudr/dds/info?uuids=UUID1,UUID2,UUID3"
Enter fullscreen mode Exit fullscreen mode

POST:

curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"uuids": ["UUID1", "UUID2", "UUID3"]}' \
  "https://www.eudr-api.eu/api/eudr/dds/info"
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "success",
  "httpStatus": 200,
  "data": [
    {
      "uuid": "UUID1",
      "info": { /* DDS information */ }
    },
    {
      "uuid": "UUID2", 
      "info": { /* DDS information */ }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3.2 Search by Internal Reference Number

Purpose: Find DDS statements using internal reference numbers

Endpoints:

  • GET /eudr/dds/info/search?internalReferenceNumber=REF123
  • POST /eudr/dds/info/search

Validation Rules:

  • internalReferenceNumber is required
  • Must be a string

Request Examples:

GET:

curl -X GET \
  -H "x-api-key: YOUR_API_KEY" \
  "https://www.eudr-api.eu/api/eudr/dds/info/search?internalReferenceNumber=HR-000002"
Enter fullscreen mode Exit fullscreen mode

POST:

curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"internalReferenceNumber": "HR-000002"}' \
  "https://www.eudr-api.eu/api/eudr/dds/info/search"
Enter fullscreen mode Exit fullscreen mode

3.3 Get Statement by Identifiers

Purpose: Retrieve final DDS statements using reference and verification numbers

Endpoints:

  • GET /eudr/dds/statement?referenceNumber=REF001&verificationNumber=VER001
  • POST /eudr/dds/statement

Validation Rules:

  • Both referenceNumber and verificationNumber are required
  • Both must be strings

Request Examples:

GET:

curl -X GET \
  -H "x-api-key: YOUR_API_KEY" \
  "https://www.eudr-api.eu/api/eudr/dds/statement?referenceNumber=REF001&verificationNumber=VER001"
Enter fullscreen mode Exit fullscreen mode

POST:

curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"referenceNumber": "REF001", "verificationNumber": "VER001"}' \
  "https://www.eudr-api.eu/api/eudr/dds/statement"
Enter fullscreen mode Exit fullscreen mode

4. DDS Amendment Service

Purpose: Modify existing DDS statements

Endpoint: PUT /eudr/dds

Validation Rules:

  • ddsIdentifier is required (string)
  • statement object is required and must not be empty

Request Example:

{
  "ddsIdentifier": "UUID-12345-67890",
  "statement": {
    "comment": "Updated comment",
    "commodities": [
      {
        "position": 1,
        "descriptors": {
          "descriptionOfGoods": "Updated timber description"
        }
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "success",
  "httpStatus": 200,
  "data": {
    "ddsIdentifier": "UUID-12345-67890",
    "message": "Amendment successful"
  }
}
Enter fullscreen mode Exit fullscreen mode

Error Response (400):

{
  "status": "error",
  "httpStatus": 400,
  "message": "DDS identifier is required"
}
Enter fullscreen mode Exit fullscreen mode

5. DDS Retraction Service

Purpose: Withdraw existing DDS statements

Endpoint: DELETE /eudr/dds

Validation Rules:

  • ddsIdentifier is required (string)

Request Example:

{
  "ddsIdentifier": "UUID-12345-67890"
}
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "success",
  "httpStatus": 200,
  "data": {
    "ddsIdentifier": "UUID-12345-67890",
    "message": "Retraction successful"
  }
}
Enter fullscreen mode Exit fullscreen mode

6. HS Codes Service

Purpose: Look up Harmonized System codes for product classification

Endpoints:

  • GET /eudr/hscodes?section=timber
  • POST /eudr/hscodes

Validation Rules:

  • section parameter is optional
  • Uses regex for partial matching (case-insensitive)
  • Returns all codes if no section specified

Request Examples:

GET:

curl -X GET \
  -H "x-api-key: YOUR_API_KEY" \
  "https://www.eudr-api.eu/api/eudr/hscodes?section=timber"
Enter fullscreen mode Exit fullscreen mode

POST:

curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"section": "timber"}' \
  "https://www.eudr-api.eu/api/eudr/hscodes"
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "success",
  "data": [
    {
      "code": "4401",
      "section": "Fuel wood, in logs, in billets, in twigs, in faggots or in similar forms"
    },
    {
      "code": "4402",
      "section": "Wood charcoal (including shell or nut charcoal), whether or not agglomerated"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

API Versioning

The API supports two versions with the x-api-eudr-version header:

  • Version 1: Legacy EUDR compliance
  • Version 2: Latest EUDR standards (default)

Version Selection:

# Use version 1
curl -H "x-api-eudr-version: 1" \
     -H "x-api-key: YOUR_API_KEY" \
     "https://www.eudr-api.eu/api/eudr/echo?message=test"

# Use version 2 (default)
curl -H "x-api-eudr-version: 2" \
     -H "x-api-key: YOUR_API_KEY" \
     "https://www.eudr-api.eu/api/eudr/echo?message=test"

# Omit header (defaults to version 2)
curl -H "x-api-key: YOUR_API_KEY" \
     "https://www.eudr-api.eu/api/eudr/echo?message=test"
Enter fullscreen mode Exit fullscreen mode

Error Handling

Common HTTP Status Codes

  • 200: Success (GET, PUT, DELETE)
  • 201: Created (POST)
  • 400: Bad Request (validation errors)
  • 401: Unauthorized (invalid/missing API key)
  • 500: Internal Server Error

Error Response Structure

{
  "status": "error",
  "httpStatus": 400,
  "message": "Validation error",
  "code": "VALIDATION_ERROR",
  "details": {
    "field": "uuids",
    "value": "",
    "msg": "Array of UUIDs is required"
  }
}
Enter fullscreen mode Exit fullscreen mode

Validation Error Examples

Missing Required Fields:

{
  "status": "error",
  "httpStatus": 400,
  "message": "Reference number and verification number are required"
}
Enter fullscreen mode Exit fullscreen mode

Invalid API Version:

{
  "status": "error",
  "httpStatus": 400,
  "message": "Invalid API version. Must be 1 or 2.",
  "code": "INVALID_API_VERSION",
  "details": {
    "providedVersion": "3",
    "allowedVersions": ["1", "2"],
    "defaultVersion": "2"
  }
}
Enter fullscreen mode Exit fullscreen mode

Complete Integration Example

Here's a full workflow example using all services:

#!/bin/bash

# Set your API key
export EUDR_API_KEY="your-api-key-here"
export API_BASE="https://www.eudr-api.eu/api/eudr"

echo "🔍 Testing connectivity..."
curl -X POST \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"ping"}' \
  "$API_BASE/echo"

echo -e "\n📝 Submitting DDS..."
curl -X POST \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @statement.json \
  "$API_BASE/dds"

echo -e "\n🔍 Retrieving DDS info..."
curl -X POST \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"uuids":["UUID1","UUID2"]}' \
  "$API_BASE/dds/info"

echo -e "\n📋 Getting statement..."
curl -X POST \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"referenceNumber":"REF001","verificationNumber":"VER001"}' \
  "$API_BASE/dds/statement"

echo -e "\n✏️ Amending DDS..."
curl -X PUT \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ddsIdentifier":"UUID123","statement":{"comment":"Updated"}}' \
  "$API_BASE/dds"

echo -e "\n🗑️ Retracting DDS..."
curl -X DELETE \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ddsIdentifier":"UUID123"}' \
  "$API_BASE/dds"

echo -e "\n🏷️ Looking up HS codes..."
curl -X POST \
  -H "x-api-key: $EUDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"section":"timber"}' \
  "$API_BASE/hscodes"
Enter fullscreen mode Exit fullscreen mode

Rate Limiting & Usage Tracking

  • Echo Service: No rate limits
  • HS Codes: No rate limits (metered usage)
  • All Other Services: There is a rate limit policy in place, but it is not strictly enforced. If you exceed your tier's limits, you will only receive warning notifications—no automatic blocking occurs. For higher or sustained usage, please contact us for an enterprise agreement. This generous approach ensures uninterrupted access while encouraging responsible use. 🚦
  • Usage Tracking: All requests are logged

Best Practices

  1. Always include API key: Every request requires x-api-key header
  2. Use appropriate HTTP methods: GET for retrieval, POST for creation, PUT for updates, DELETE for removal
  3. Handle errors gracefully: Check HTTP status codes and error messages
  4. Validate data: Ensure required fields are present before sending
  5. Use versioning: Specify x-api-eudr-version if you need specific behavior
  6. Monitor usage: Track your API calls to stay within limits

Helpful Resources

  • Website: www.eudr-api.eu - Main platform and documentation
  • Registration: www.eudr-api.eu/register - Get your free API key
  • Dashboard: www.eudr-api.eu/dashboard - Manage your API keys and usage
  • Medium Tutorial: "How to Integrate with the EUDR Traces API using Node.js" - provides background context and integration patterns with our open source eudr-api-client
  • Open Source Client: eudr-api-client - Node.js library for EUDR TRACES system integration with automatic endpoint generation and comprehensive validation
  • API Documentation: Interactive docs available at www.eudr-api.eu/api-docs

Conclusion

The www.eudr-api.eu platform provides a comprehensive, production-ready solution for EUDR compliance. With standardized endpoints, consistent response formats, and robust validation, you can integrate EUDR compliance into your applications quickly and reliably.

The API handles the complexity of EUDR requirements while providing a clean, RESTful interface that developers can easily work with. Whether you're building compliance dashboards, integrating with existing systems, or creating new compliance workflows, this API gives you the tools you need.

Start with the echo endpoint to test connectivity, then explore the DDS services to understand the full compliance workflow. The comprehensive validation and error handling ensure you'll get clear feedback on any issues, making integration straightforward and reliable.

Ready to get started? Register for free at www.eudr-api.eu and begin your EUDR compliance journey today!


*This guide covers the complete www.eudr-api.eu EUDR API based on the actual implementation. For more information about our solutions or to discuss how we can help with your compliance needs, visit our website or reach out to our team.

Top comments (0)