Pull your own EUDR compliance records directly into your procurement or ERP software โ no manual exports, no waiting on someone to send a PDF. Available on the Business ($399/mo) and EUDR Enterprise ($599/mo) plans.
API keys are generated from your Enterprise Profile โ no separate developer account needed. Go to app.timberlark.com/enterprise-profile and scroll to the "API Access" section. If your account is on the Business or EUDR Enterprise plan, you can generate a key immediately.
Your key is shown exactly once at creation time. Store it securely โ Timberlark never stores the plaintext key and cannot retrieve it for you if lost. If a key is lost or compromised, revoke it and generate a new one.
Every request must include your API key as a Bearer token in the Authorization header:
Authorization: Bearer tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Requests without a valid, non-revoked key โ or from an account whose subscription has lapsed below Business tier โ receive a 401 or 403 response.
Each API key is limited to 60 requests per rolling 60-second window. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers so you can back off before hitting the limit. Exceeding it returns 429 with a Retry-After header (in seconds).
This is generous for polling-based integrations โ if you're calling more often than once a second, register a webhook instead and let Timberlark push new records to you.
Returns your account's EUDR due diligence records, most recent first โ GPS-tagged harvest data, species, certifications, blockchain transaction IDs, and satellite deforestation-check results for every statement you've filed.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max records to return. Default 50, max 200. |
since | ISO 8601 date | Only return records created on or after this date โ useful for incremental syncs. |
curl "https://app.timberlark.com/api/v1/eudr-records?limit=20&since=2026-07-01" \
-H "Authorization: Bearer tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
The API is plain REST/JSON โ no SDK install required. Here's the same request in a few common environments:
// Node.js (fetch, built in since Node 18)
const res = await fetch(
"https://app.timberlark.com/api/v1/eudr-records?limit=20",
{ headers: { Authorization: "Bearer tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } }
);
if (res.status === 429) {
const retryAfter = res.headers.get("Retry-After");
// back off and retry after `retryAfter` seconds
}
const { records } = await res.json();
# Python (requests)
import requests
resp = requests.get(
"https://app.timberlark.com/api/v1/eudr-records",
params={"limit": 20},
headers={"Authorization": "Bearer tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"},
)
resp.raise_for_status()
records = resp.json()["records"]
// C# (HttpClient โ common in SAP/Dynamics integrations)
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
var response = await client.GetAsync(
"https://app.timberlark.com/api/v1/eudr-records?limit=20");
var json = await response.Content.ReadAsStringAsync();
{
"fetchedAt": "2026-07-29T14:02:11.000Z",
"count": 2,
"limit": 20,
"records": [
{
"id": "b2f1c9a0-...",
"statement_number": "TL-EUDR-20260703-4821",
"company_name": "Nordic Timber Exports GmbH",
"harvest_country": "Sweden",
"harvest_region": "Norrland",
"species": "Pine (Pinus spp.); Spruce (Picea spp.)",
"volume_tons": "480",
"gps_lat": "65.0987",
"gps_lng": "16.8321",
"deforestation_declaration": true,
"satellite_check": { "clean": true, "alerts": [] },
"blockchain_record": {
"txId": "0x7f3a8c2d...",
"network": "mainnet",
"explorerUrl": "https://explore.vechain.org/transactions/0x7f3a8c2d...",
"filedAt": "2026-07-03T14:32:07.000Z"
},
"created_at": "2026-07-03T14:32:07.000Z"
}
]
}
Returns your account's own jobs โ whether you posted them or are the accepted party fulfilling them โ including custody chain, compliance status, and blockchain event data. Same auth, rate limiting, and limit/since parameters as /eudr-records above.
curl "https://app.timberlark.com/api/v1/jobs?limit=20" \
-H "Authorization: Bearer tl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
{
"fetchedAt": "2026-08-01T00:02:11.000Z",
"count": 1,
"limit": 20,
"jobs": [
{
"id": "9a2c1e40-...",
"title": "40-acre Loblolly Pine Harvest",
"location": "Valdosta, GA",
"commodity_key": "timber",
"job_type": "logging",
"status": "in_progress",
"posted_by": "Jane R.",
"posted_by_role": "landowner",
"accepted_by": "Timber Solutions LLC",
"compliance_type": "eudr",
"compliance_data": { "statement_number": "TL-EUDR-20260703-4821" },
"custody_chain": [
{ "step": "harvested", "at": "2026-07-01T10:00:00.000Z", "gps": { "lat": 30.83, "lng": -83.28 } }
],
"vechain_events": [],
"created_at": "2026-06-28T09:00:00.000Z",
"updated_at": "2026-07-01T10:00:00.000Z"
}
]
}
Instead of polling GET /api/v1/eudr-records, register a webhook URL from your Enterprise Profile's "Webhooks" section and Timberlark will push a signed notification to it the instant a new EUDR record is filed on your account โ no polling required.
eudr_record.createdFires once, immediately, whenever a new EUDR due diligence statement is filed under your account.
Timberlark sends an HTTP POST to your registered URL with a JSON body and two custom headers:
POST /your-endpoint HTTP/1.1
Content-Type: application/json
X-Timberlark-Event: eudr_record.created
X-Timberlark-Signature: 284ac72efcdef65ffea8d61b00c8a7951d90961e88b372d63216594811dd2609
{
"event": "eudr_record.created",
"timestamp": "2026-07-31T00:52:34Z",
"data": {
"id": "55b34e9a-7b15-4422-b85a-44e20bda0185",
"statement_number": "TL-EUDR-20260703-4821",
"company_name": "Nordic Timber Exports GmbH",
"harvest_country": "Sweden",
"species": "Pine (Pinus spp.); Spruce (Picea spp.)",
"created_at": "2026-07-03T14:32:07.000Z"
}
}
X-Timberlark-Signature is an HMAC-SHA256 of the exact request body, hex-encoded, signed with the secret shown once when you registered the webhook. Verify it before trusting the payload:
// Node.js example
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
https:// โ plain HTTP is not accepted.2xx within 5 seconds, delivery is retried automatically with backoff (roughly 2min, 5min, 15min, then 30min) for up to 5 total attempts over about an hour before we give up. You don't need to build your own retry handling for transient downtime.GET /api/v1/eudr-records with the since parameter as a periodic backstop to catch anything missed after all retries are exhausted.Retry-After header before retrying.If your procurement or ERP team needs help wiring this up, reach out directly โ we'll work with your developers.
Contact Us โ