Webhooks
Receive a TRACES NT Clearance Status Webhook Event
Inbound event from AgriBackup when TRACES NT posts a DDS clearance decision — validated, rejected, or pending — for a compliance declaration.
POST
/
api
/
v1
/
enterprise
/
eudr
/
clearance
/
webhook
Python
import agribackup
from agribackup.rest import ApiException
# Initialize Client
configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
api_instance = agribackup.EnterpriseClearanceWebhooksApi(api_client)
response = api_instance.handle_clearance_webhook()
print(response)
except ApiException as e:
print("Exception when calling API: %s\n" % e)import { AgriBackupClient } from '@agribackup/sdk';
// Initialize Client
const client = new AgriBackupClient({
apiKey: 'sk_live_YOUR_API_KEY',
baseUrl: 'https://live.agribackup.com/api/v1'
});
async function execute() {
try {
const response = await client.webhooks.handleClearanceWebhook();
console.log(response);
} catch (error) {
console.error(error);
}
}import com.agribackup.client.*;
import com.agribackup.client.api.*;
import com.agribackup.client.model.*;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://live.agribackup.com/api/v1");
defaultClient.setApiKey("sk_live_YOUR_API_KEY");
EnterpriseClearanceWebhooksApi apiInstance = new EnterpriseClearanceWebhooksApi(defaultClient);
try {
Object result = apiInstance.handleClearanceWebhook();
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling API: " + e.getResponseBody());
}
}
}using System;
using System.Threading.Tasks;
using AgriBackup.SDK.Api;
using AgriBackup.SDK.Client;
using AgriBackup.SDK.Model;
class Program {
static async Task Main() {
Configuration config = new Configuration();
config.BasePath = "https://live.agribackup.com/api/v1";
config.AddApiKey("ApiKeyAuth", "sk_live_YOUR_API_KEY");
var apiInstance = new EnterpriseClearanceWebhooksApi(config);
try {
var result = await apiInstance.HandleClearanceWebhookAsync();
Console.WriteLine(result);
} catch (ApiException e) {
Console.WriteLine("Exception when calling API: " + e.Message);
}
}
}curl --request POST \
--url https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook \
--header 'Content-Type: application/json' \
--data '
{
"tracesReferenceNumber": "<string>",
"status": "<string>",
"timestamp": "<string>"
}
'const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({tracesReferenceNumber: '<string>', status: '<string>', timestamp: '<string>'})
};
fetch('https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tracesReferenceNumber' => '<string>',
'status' => '<string>',
'timestamp' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook"
payload := strings.NewReader("{\n \"tracesReferenceNumber\": \"<string>\",\n \"status\": \"<string>\",\n \"timestamp\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"tracesReferenceNumber\": \"<string>\",\n \"status\": \"<string>\",\n \"timestamp\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{}This endpoint describes an inbound webhook event that AgriBackup delivers to your registered callback URL when the TRACES NT system posts a clearance status update for a Due Diligence Statement (DDS) you submitted. You do not call this endpoint directly — AgriBackup calls your server.
When TRACES NT issues a clearance decision (e.g.,
VALIDATED, REJECTED, or PENDING), AgriBackup wraps the status update in a signed payload and delivers it to the URL you registered via Register Webhook Endpoint. The payload is signed with HMAC-SHA256 and included in the X-AgriBackup-Signature header — verify the signature before processing.
Payload Shape
{
"tracesReferenceNumber": "TRACES-2026-EU-000123",
"status": "VALIDATED",
"timestamp": "2026-06-12T14:30:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
tracesReferenceNumber | string | ✅ | The official TRACES NT reference number for the DDS |
status | string | ✅ | Clearance decision from TRACES NT — e.g., VALIDATED, REJECTED, PENDING |
timestamp | string | — | ISO-8601 timestamp of the clearance decision |
Handling the Event
Your endpoint must return HTTP200 OK to acknowledge receipt. A non-2xx response is treated as a delivery failure and triggers AgriBackup’s standard retry policy. If retries are exhausted, the message is moved to the Dead-Letter Queue and can be retrieved via Retrieve Permanently Failed Webhook Payloads.
import hmac
import hashlib
from flask import Flask, request, abort
app = Flask(__name__)
SIGNING_SECRET = "whsec_YOUR_SIGNING_SECRET"
@app.route("/agribackup-webhooks", methods=["POST"])
def receive_clearance_webhook():
raw_body = request.get_data()
header_sig = request.headers.get("X-AgriBackup-Signature", "")
computed = hmac.new(
SIGNING_SECRET.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(computed, header_sig):
abort(401)
payload = request.get_json()
traces_ref = payload["tracesReferenceNumber"]
status = payload["status"]
# Update DDS record in your ERP
print(f"DDS {traces_ref} is now {status}")
return "", 200
const crypto = require("crypto");
const express = require("express");
const app = express();
const SIGNING_SECRET = "whsec_YOUR_SIGNING_SECRET";
app.post(
"/agribackup-webhooks",
express.raw({ type: "application/json" }),
(req, res) => {
const headerSig = req.headers["x-agribackup-signature"] || "";
const computed = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(req.body)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(headerSig))) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body);
const { tracesReferenceNumber, status } = payload;
// Update DDS record in your ERP
console.log(`DDS ${tracesReferenceNumber} is now ${status}`);
res.sendStatus(200);
}
);
Permanently Delete an EUDR Webhook Registration
Previous
List Permanently Failed EUDR Webhook DLQ Payloads
Next
⌘I
Python
import agribackup
from agribackup.rest import ApiException
# Initialize Client
configuration = agribackup.Configuration(host="https://live.agribackup.com/api/v1")
configuration.api_key['ApiKeyAuth'] = 'sk_live_YOUR_API_KEY'
with agribackup.ApiClient(configuration) as api_client:
try:
api_instance = agribackup.EnterpriseClearanceWebhooksApi(api_client)
response = api_instance.handle_clearance_webhook()
print(response)
except ApiException as e:
print("Exception when calling API: %s\n" % e)import { AgriBackupClient } from '@agribackup/sdk';
// Initialize Client
const client = new AgriBackupClient({
apiKey: 'sk_live_YOUR_API_KEY',
baseUrl: 'https://live.agribackup.com/api/v1'
});
async function execute() {
try {
const response = await client.webhooks.handleClearanceWebhook();
console.log(response);
} catch (error) {
console.error(error);
}
}import com.agribackup.client.*;
import com.agribackup.client.api.*;
import com.agribackup.client.model.*;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://live.agribackup.com/api/v1");
defaultClient.setApiKey("sk_live_YOUR_API_KEY");
EnterpriseClearanceWebhooksApi apiInstance = new EnterpriseClearanceWebhooksApi(defaultClient);
try {
Object result = apiInstance.handleClearanceWebhook();
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling API: " + e.getResponseBody());
}
}
}using System;
using System.Threading.Tasks;
using AgriBackup.SDK.Api;
using AgriBackup.SDK.Client;
using AgriBackup.SDK.Model;
class Program {
static async Task Main() {
Configuration config = new Configuration();
config.BasePath = "https://live.agribackup.com/api/v1";
config.AddApiKey("ApiKeyAuth", "sk_live_YOUR_API_KEY");
var apiInstance = new EnterpriseClearanceWebhooksApi(config);
try {
var result = await apiInstance.HandleClearanceWebhookAsync();
Console.WriteLine(result);
} catch (ApiException e) {
Console.WriteLine("Exception when calling API: " + e.Message);
}
}
}curl --request POST \
--url https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook \
--header 'Content-Type: application/json' \
--data '
{
"tracesReferenceNumber": "<string>",
"status": "<string>",
"timestamp": "<string>"
}
'const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({tracesReferenceNumber: '<string>', status: '<string>', timestamp: '<string>'})
};
fetch('https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tracesReferenceNumber' => '<string>',
'status' => '<string>',
'timestamp' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook"
payload := strings.NewReader("{\n \"tracesReferenceNumber\": \"<string>\",\n \"status\": \"<string>\",\n \"timestamp\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://live.agribackup.com/api/v1/enterprise/eudr/clearance/webhook")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"tracesReferenceNumber\": \"<string>\",\n \"status\": \"<string>\",\n \"timestamp\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{}