← veridyn.eu
HU EN DE

Developer API v1

veridyn

Programmatic access to product passports — for webshop/ERP sync and bulk automation.

From the Pro plan

During the open beta the API is available to every beta account — the Pro requirement applies after the beta.

Authentication

Every request authenticates with an API key, in the Authorization header:

Authorization: Bearer vk_<your key>

You create a key under Settings → Developer API. The plaintext key is shown only once, at creation — store it safely. The key grants read/write access to all products in your account, so keep it confidential.

Quick test in the browser

The key goes only in the Authorization header — not as a URL parameter, for security (it would end up in browser history and server logs). Try it for example with curl:

curl -H "Authorization: Bearer vk_<your key>" https://veridyn.eu/api/v1/categories

Key scope

When creating a key you choose a scope: Full (read + write) or Read-only. A read-only key may only call GETPOST/PATCH/DELETE return 403 read_only. Use a read-only key for ERP or display integrations.

Rate limit

Per key, 120–600 requests / minute depending on plan (Pro 120 · Business 300 · Enterprise 600; 300 during the open beta). Every response includes the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix time) headers. Exceeding the limit returns 429 rate_limited with a Retry-After header — wait the indicated time, then retry.

Idempotency

You can add a unique Idempotency-Key header to POST requests. If you resend it with the same key (e.g. after a network error), you get back the original response — no duplicate is created. A replayed response is marked with the Idempotency-Replayed: true header.

OpenAPI

Machine-readable API description (OpenAPI 3.1) — for Postman import and SDK/code generation:

https://veridyn.eu/api/v1/openapi.json

⚡ Interactive API reference

Browsable, searchable endpoint reference — rendered directly from the spec above.

DPP vocabulary (JSON-LD namespace)

The machine-readable passport is JSON-LD: standard fields come from schema.org, DPP-specific fields from the dpp: namespace. That namespace is resolvable — open it to see what every field means, or send Accept: application/ld+json to get the machine-readable @context document.

https://veridyn.eu/ns/dpp/v1/

A single passport as data: its public URL with ?format=jsonld (or an Accept: application/ld+json header).

Postman collection

A ready-to-import collection with pre-set variables and example requests. After importing, just fill in the base_url and api_key collection variables.

⬇ Download Postman collection

Generate your own SDK

From the OpenAPI spec you can generate an official client in any language with openapi-generator — no hand-maintained SDK, always up to date. E.g. PHP:

npx @openapitools/openapi-generator-cli generate \
  -i https://veridyn.eu/api/v1/openapi.json \
  -g php -o ./veridyn-sdk

The -g value can be typescript-fetch, python, java and many more.

Quickstart (code)

PHP

$ch = curl_init('https://veridyn.eu/api/v1/products?limit=5');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => ['Authorization: Bearer vk_...'],
]);
$products = json_decode(curl_exec($ch), true)['data'];

JavaScript (fetch)

const res = await fetch('https://veridyn.eu/api/v1/products?limit=5', {
  headers: { 'Authorization': 'Bearer vk_...' }
});
const { data } = await res.json();

Base URL

https://veridyn.eu/api/v1

Responses are application/json, UTF-8 encoded.

Endpoints

MethodPathDescription
GET/categoriesAvailable product categories.
GET/schema/{category}The category's full field list — required + optional, type, enum, localized fields.
GET/productsList of products (summary). Parameters: q, status, page, limit.
POST/productsNew product passport. Body: { category, data }.
GET/products/{id}A product's full data + passport URL.
PATCH/products/{id}Update (partial) — creates a new version. Body: { data, change_type? }. change_type is optional: correction (the model held wrong data → already-issued batch/unit passports become out of date and can be refreshed) or change (the product changed from a given date → earlier units keep their correct data and are not overwritten).
GET/products/{id}/qrQR code (SVG) for the public passport.
GET/products/{id}/childrenList of the batch/unit child passports.
POST/products/{id}/childrenBatch/unit passport. Single: { level, lot|serial, data } · bulk: { level, items:[…] } (max 500). Inherits the parent's data.
GET/products/{id}/scansPer-product scan summary: total, unique, byCountry, byDevice. Parameter: days=7|30|90|365.
GET/scansTenant-wide scan summary: the above + byCategory, byLevel.

What to send? (required vs. optional)

Every category has a required core — without it, schema validation rejects the request (422). All other fields are optional, but you can send them in the same data object anytime (more data = a better passport and more future-proof compliance). The exact, machine-readable field list is returned by /schema/{category} — with required: true/false, type, enum and localized markers.

curl https://veridyn.eu/api/v1/schema/textile \
  -H "Authorization: Bearer vk_<key>"

All fields by category

= required · = optional · nested sub-field · 🌐 per-language (localized) · 🔒 visible only at authority level. This list is generated from the schema — always up to date.

textile Textile & apparel20 fields

FieldTypeReq.Description
productNamestringProduct name — The product name as the buyer will see it on the passport.
skustringSKU — Internal item number / identifier — from your own system.
brandNamestringBrand
gtinstringGTIN (optional) — The barcode number (GTIN-8/12/13/14). The system validates the check digit. Leave empty if you don't have one.
commodityCodestringCommodity code (CN/HS, optional) — Customs/tariff classification: Combined Nomenclature (CN, 8 digits) or HS code. Mandatory metadata of the EU DPP register at registration — it appears on your supplier/customs documents.
economicOperatorobjectEconomic operator
  ↳ rolestring (enum)Role — Who places the product on the EU market and is responsible for it. For most manufacturers: Manufacturer. (manufacturer · importer · authorized_representative · distributor · dealer · fulfilment_service_provider)
  ↳ legalNamestringLegal name
  ↳ addressstringAddress
  ↳ countrystringCountry (ISO 3166-1 alpha-2) — Two-letter ISO country code, in capitals — e.g. HU, DE, IT
  ↳ contactEmailstringContact email — This is where the buyer or an authority can turn.
  ↳ operatorIdstringUnique operator ID (GS1 GLN) — 13-digit GS1 GLN — the EU DPP unique economic operator identifier. Leave empty if you don't have one.
  ↳ eori 🔒stringEORI number — The economic operator's EORI number (customs / EU DPP registry identifier) — the registry identifies you by this. Visible only at authority access level. Leave empty if you don't have one.
languagesarray[string]Languages (BCP-47) — Which languages the passport should appear in. The localised fields (care, life cycle) must be filled in for every language listed here. e.g. hu, en
fiberCompositionarray[object]Fibre composition — What the product is made of. The percentages must add up to exactly 100. e.g. cotton 95 + elastane 5
  ↳ fiberstringFibre
  ↳ percentagenumberPercentage
recycledContentPercentagenumberRecycled content — The share of recycled content in the product. Leave empty if not relevant.
countryOfManufacturestringCountry of manufacture (ISO) — Where the finished product was made. Two-letter ISO code, e.g. PT, TR, HU
supplyChainStagesarray[object]Supply chain stages — Where each production step took place (spinning, weaving, dyeing, assembly…). Optional, but it builds trust. The step and the country are public; the facility name and ID are protected — only a legitimate interest party (and authorities) can see them, via a token link.
  ↳ stagestring (enum)Stage (spinning · weaving · knitting · dyeing · finishing · assembly)
  ↳ countrystringCountry (ISO)
  ↳ facilityName 🔒stringFacility name
  ↳ facilityId 🔒stringUnique facility ID (GS1 GLN)
careInstructions 🌐objectCare instructions — Washing, drying, ironing — one text per language.
repairobjectRepairability — Whether and how it can be repaired. The “repairable” and “spare parts available” fields are mandatory.
  ↳ repairablebooleanRepairable
  ↳ instructions 🌐objectRepair instructions — How it can be repaired — per language (optional).
  ↳ sparePartsAvailablebooleanSpare parts available (e.g. button, zip)
substancesOfConcernarray[object]Substances of concern — Substances of concern (e.g. REACH SVHC), if present in the product. Can be left empty for most products.
  ↳ namestringName
  ↳ casNumberstringCAS number
  ↳ concentrationRangestringConcentration range
durabilityobjectDurability — Durability data, if you have measurements (optional).
  ↳ testResultsstringTest results
  ↳ pefScorenumberPEF score — Product Environmental Footprint score, if available. (optional)
carbonFootprintnumberCarbon footprint (kg CO₂e) — The product's total carbon footprint in kg CO₂ equivalent. Shown in the “Impact” theme as an “≈ km by car” comparison.
waterFootprintnumberWater footprint (litres) — The amount of water used in manufacturing, in litres. Optional.
weightGramsnumberWeight (grams) — The product's weight in grams. Optional.
endOfLifeobjectEnd of life — What should happen to the product after use — filled in for each language.
  ↳ recyclingInstructions 🌐objectRecycling instructions — How it can be recycled — per language.
  ↳ disposalInstructions 🌐objectDisposal instructions — If it is not recyclable — per language.
complianceDocumentsarray[object]Compliance documents — Links to certificates and conformity documents (optional). e.g. OEKO-TEX, GOTS.
  ↳ typestringType
  ↳ urlstringURL

battery Battery27 fields

FieldTypeReq.Description
productNamestringProduct name — The battery name as the buyer will see it on the passport.
skustringSKU — Internal item number / identifier — from your own system.
brandNamestringBrand
gtinstringGTIN (optional) — The barcode number (GTIN-8/12/13/14). The system validates the check digit. Leave empty if you don't have one.
commodityCodestringCommodity code (CN/HS, optional) — Customs/tariff classification: Combined Nomenclature (CN, 8 digits) or HS code. Mandatory metadata of the EU DPP register at registration — it appears on your supplier/customs documents.
economicOperatorobjectEconomic operator
  ↳ rolestring (enum)Role — Who places the product on the EU market and is responsible for it. For most manufacturers: Manufacturer. (manufacturer · importer · authorized_representative · distributor · dealer · fulfilment_service_provider)
  ↳ legalNamestringLegal name
  ↳ addressstringAddress
  ↳ countrystringCountry (ISO 3166-1 alpha-2) — Two-letter ISO country code, in capitals — e.g. HU, DE, IT
  ↳ contactEmailstringContact email — This is where the buyer or an authority can turn.
  ↳ operatorIdstringUnique operator ID (GS1 GLN) — 13-digit GS1 GLN — the EU DPP unique economic operator identifier. Leave empty if you don't have one.
  ↳ eori 🔒stringEORI number — The economic operator's EORI number (customs / EU DPP registry identifier) — the registry identifies you by this. Visible only at authority access level. Leave empty if you don't have one.
languagesarray[string]Languages (BCP-47) — Which languages the passport should appear in. The localised fields (safety, life cycle) must be filled in for every language listed here. e.g. hu, en
batteryCategorystring (enum)Battery category — The category under (EU) 2023/1542. The mandatory passport applies first to EV, industrial (>2 kWh) and LMT batteries (18 February 2027). (portable · lmt · ev · industrial · sli)
cellChemistrystring (enum)Cell chemistry — The battery's cell chemistry type. (nmc · nca · lfp · lmo · lto · nimh · lead_acid · sodium_ion …)
weightKgnumberWeight (kg) — The battery's weight in kilograms.
countryOfManufacturestringCountry of manufacture (ISO) — Where the battery was made. Two-letter ISO code, e.g. DE, HU, CN
manufacturingDatestringManufacturing date / year — The year or year-month of manufacture, in ISO format: YYYY, YYYY-MM or YYYY-MM-DD.
ratedCapacitynumberRated capacity (Ah) — Nominal capacity in ampere-hours (Ah).
energyWhnumberEnergy (Wh) — Total energy content in watt-hours (Wh). Optional.
nominalVoltagenumberNominal voltage (V) — Nominal voltage in volts. Optional.
expectedLifetimeCyclesnumberExpected lifetime (charge cycles) — The guaranteed / expected total number of charging cycles. Optional.
stateOfHealth 🔒numberState of Health — The battery's state of health as a % of the original capacity (100 for a new battery). UNIT-SPECIFIC and dynamic — its ideal place is the unit level (not the model template). Optional.
carbonFootprintnumberCarbon footprint (kg CO₂e / kWh) — The battery's carbon footprint over the full life cycle, in kg CO₂ equivalent per kWh of total energy.
carbonFootprintClassstringCarbon footprint class (A–G) — The CF performance class under the regulation, if available. Optional.
carbonFootprintStudyUrlstringCarbon footprint study (URL) — Link to the study / documentation underlying the carbon footprint calculation (per the CF delegated act). Optional.
carbonFootprintBreakdownarray[object]Carbon footprint by lifecycle stage — Breakdown of the carbon footprint by life cycle stage (kg CO₂e / kWh) — this is what the CF delegated act expects. Optional.
  ↳ stagestring (enum)Lifecycle stage (raw_material · main_production · distribution · recycling)
  ↳ valuenumberValue (kg CO₂e / kWh)
recycledContentarray[object]Recycled raw-material content — The share of recycled critical raw materials per material (cobalt, lithium, nickel, lead). Optional, but the regulation expects it ever more strictly.
  ↳ materialstring (enum)Material (cobalt · lithium · nickel · lead)
  ↳ percentagenumberRecycled share
hazardousSubstancesarray[object]Hazardous substances — Hazardous substances present in the battery (beyond mercury, cadmium and lead). Relevant for most data sheets.
  ↳ namestringName
  ↳ casNumberstringCAS number
  ↳ concentrationRangestringConcentration range
safetyInformation 🌐objectSafety information — Handling, storage and emergency information — one text per language.
dueDiligenceUrl 🔒stringSupply chain due diligence report (URL) — Link to the due diligence policy/report required by the regulation. Legitimate interest access level (Art. 77(4)) — not public. Optional.
endOfLifeobjectEnd of life — Collection, recycling, disassembly — filled in for each language.
  ↳ recyclingInstructions 🌐objectCollection / recycling — Where it can be returned and how it can be recycled — per language.
  ↳ disposalInstructions 🌐objectDisposal / warnings — Prohibitions, hazards — per language.
complianceDocumentsarray[object]Compliance documents — Links to certificates, conformity and test documents (optional). e.g. CE, UN 38.3.
  ↳ typestringType
  ↳ urlstringURL

furniture Furniture20 fields

FieldTypeReq.Description
productNamestringProduct name — The product name as the buyer will see it on the passport.
skustringSKU — Internal item number / identifier — from your own system.
brandNamestringBrand
gtinstringGTIN (optional) — The barcode number (GTIN-8/12/13/14). The system validates the check digit. Leave empty if you don't have one.
commodityCodestringCommodity code (CN/HS, optional) — Customs/tariff classification: Combined Nomenclature (CN, 8 digits) or HS code. Mandatory metadata of the EU DPP register at registration — it appears on your supplier/customs documents.
economicOperatorobjectEconomic operator
  ↳ rolestring (enum)Role — Who places the product on the EU market and is responsible for it. For most manufacturers: Manufacturer. (manufacturer · importer · authorized_representative · distributor · dealer · fulfilment_service_provider)
  ↳ legalNamestringLegal name
  ↳ addressstringAddress
  ↳ countrystringCountry (ISO 3166-1 alpha-2) — Two-letter ISO country code, in capitals — e.g. HU, DE, IT
  ↳ contactEmailstringContact email — This is where the buyer or an authority can turn.
  ↳ operatorIdstringUnique operator ID (GS1 GLN) — 13-digit GS1 GLN — the EU DPP unique economic operator identifier. Leave empty if you don't have one.
  ↳ eori 🔒stringEORI number — The economic operator's EORI number (customs / EU DPP registry identifier) — the registry identifies you by this. Visible only at authority access level. Leave empty if you don't have one.
languagesarray[string]Languages (BCP-47) — Which languages the passport should appear in. The localised fields (care, assembly, life cycle) must be filled in for every language listed here. e.g. hu, en
materialCompositionarray[object]Material composition — What the furniture is made of. The percentages must add up to exactly 100. e.g. solid oak 80 + metal 20
  ↳ materialstring (enum)Material (wood · engineeredWood · metal · plastic · glass · textile · foam · leather …)
  ↳ percentagenumberPercentage
woodCertificationobjectWood origin & certification — Sustainable sourcing and certification of the wood used, if relevant (optional).
  ↳ schemestring (enum)Certification scheme — Sustainable forest management certification of the wood. (fsc · pefc · none)
  ↳ countrystringCountry of origin (ISO) — Country of origin of the wood. Two-letter ISO code, e.g. AT, SE, RO. Optional.
dimensionsobjectDimensions & weight — Overall dimensions and weight of the furniture (optional).
  ↳ widthnumberWidth (cm)
  ↳ depthnumberDepth (cm)
  ↳ heightnumberHeight (cm)
  ↳ weightKgnumberWeight (kg)
countryOfManufacturestringCountry of manufacture (ISO) — Where the finished product was made. Two-letter ISO code, e.g. PL, RO, HU
careInstructions 🌐objectCare instructions — Cleaning, care, surface maintenance — one text per language.
assemblyInstructions 🌐objectAssembly instructions — How the furniture is assembled — per language (optional). A link can also be given.
repairobjectRepairability — Whether and how it can be repaired. The “repairable” and “spare parts available” fields are mandatory.
  ↳ repairablebooleanRepairable
  ↳ instructions 🌐objectRepair instructions — How it can be repaired — per language (optional).
  ↳ sparePartsAvailablebooleanSpare parts available (e.g. fittings, leg)
  ↳ sparePartsUrlstringSpare parts (URL) — Where spare parts can be ordered (optional).
warrantyMonthsnumberWarranty (months) — The length of the manufacturer's warranty in months. Optional.
substancesOfConcernarray[object]Substances of concern — Substances of concern (e.g. REACH SVHC / SCIP), if present in the product. Can be left empty for most products.
  ↳ namestringName
  ↳ casNumberstringCAS number
  ↳ notestringNote
flameRetardantsstring (enum)Flame retardants — Whether the product (especially the upholstery / foam) contains flame retardant chemicals. Optional. (present · absent · unknown)
complianceDocumentsarray[object]Compliance documents — Links to certificates and conformity documents (optional). e.g. EN 12520, EN 1728, fire safety certificate.
  ↳ typestringType
  ↳ urlstringURL
packagingstring (enum)Packaging recyclability — Recyclability of the product's packaging. Optional. (recyclable · partiallyRecyclable · notRecyclable)
endOfLifeobjectEnd of life — What should happen to the furniture after use — filled in for each language.
  ↳ recyclingInstructions 🌐objectRecycling instructions — How it can be taken apart and recycled — per language.
  ↳ disposalInstructions 🌐objectDisposal instructions — If it is not recyclable — per language.

Languages

The languages field (e.g. ["hu","en"]) declares which languages have free-text content. The localized fields (care, end-of-life… — "localized": true in /schema) must be filled only in the first (primary) language; the rest are optional, falling back to an available language if missing. The passport's UI labels are translated to 24 languages automatically, independently of this.

Examples

Create a product

curl -X POST https://veridyn.eu/api/v1/products \
  -H "Authorization: Bearer vk_<key>" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "textile",
    "data": {
      "productName": "Organic cotton tee",
      "sku": "TEE-001",
      "brandName": "Lumora",
      "languages": ["hu","en"],
      "fiberComposition": [{"fiber":"pamut","percentage":100}],
      "countryOfManufacture": "PT",
      "careInstructions": {"hu":"Mosás 30 °C","en":"Wash at 30 °C"},
      "repair": {"repairable": true, "sparePartsAvailable": false},
      "endOfLife": {
        "recyclingInstructions": {"hu":"Textilgyűjtő","en":"Textile bin"},
        "disposalInstructions": {"hu":"Ne a kukába","en":"Not household waste"}
      },
      "economicOperator": {
        "role":"manufacturer","legalName":"Lumora Kft.","address":"Budapest",
        "country":"HU","contactEmail":"[email protected]"
      }
    }
  }'

Response (201):

{
  "data": {
    "id": "a1993ef7-7562-43bb-92ff-eb63f02dcde9",
    "category": "textile",
    "status": "active",
    "version_no": 1,
    "passport_url": "https://veridyn.eu/<account>/p/a1993ef7-…",
    "qr_url": "https://veridyn.eu/api/v1/products/a1993ef7-…/qr",
    "data": { "productName": "Organic cotton tee", … }
  }
}

List

curl https://veridyn.eu/api/v1/products?limit=25 \
  -H "Authorization: Bearer vk_<key>"

Get a product

curl https://veridyn.eu/api/v1/products/{id} \
  -H "Authorization: Bearer vk_<key>"

Update (new version)

curl -X PATCH https://veridyn.eu/api/v1/products/{id} \
  -H "Authorization: Bearer vk_<key>" \
  -H "Content-Type: application/json" \
  -d '{"data": {"recycledContentPercentage": 30}}'

The provided fields are merged onto the existing data (partial update), then validated, and a new, retained version is created — the full change history is preserved.

Batch and unit passports (serialisation)

Create batch or unit passports under a model; the child inherits the parent's data — you pass only the instance-specific fields (lot/serial). Many at once (items[], max 500); the response reports success/error per item.

curl -X POST https://veridyn.eu/api/v1/products/{id}/children \
  -H "Authorization: Bearer vk_<key>" \
  -H "Content-Type: application/json" \
  -d '{"level":"item","items":[{"serial":"SN-0001"},{"serial":"SN-0002"}]}'

The {id} may be a model or a batch. POST to a batch id with level:"item" and the unit is created under that batch, inheriting its lot — its GS1 link is then …/10/lot/21/serial rather than …/21/serial. This is how the full model → batch → unit chain is built.

Scan analytics

Aggregated QR-scan statistics — per product or account-wide — broken down by country and device. Privacy: no raw IP; unique visitors are an anonymous hashed estimate.

curl "https://veridyn.eu/api/v1/products/{id}/scans?days=30" \
  -H "Authorization: Bearer vk_<key>"
{
  "data": {
    "product_id": "a1993ef7-…",
    "range_days": 30,
    "total": 189, "unique": 142,
    "byCountry": { "HU": 142, "DE": 38, "AT": 9 },
    "byDevice":  { "mobile": 168, "tablet": 9, "desktop": 12 }
  }
}

Response & errors

Success: the payload is under the data key. On error:

{ "error": "Invalid data.", "code": "validation", "errors": [ … ] }
HTTPcodeMeaning
401unauthorizedMissing/invalid API key.
403plan_requiredThe API is available from the Pro plan (during the open beta, every beta account can use it).
404not_foundNo such product / route.
409gtin_takenThe GTIN is already taken.
403plan_limitYou reached the level's quota (plan + extra). In bulk calls, the overflowing items go into errors.
422validationInvalid data (details in errors).

Webhooks

Under Settings → Webhooks you register an HTTPS URL. When a product passport is created / updated / archived, Veridyn POSTs a signed JSON to that URL — so your system is notified in real time, without polling.

Events

product.created · product.updated · product.archived · product.restored · scan.milestone · scan.clone_suspected

The scan.milestone fires when a passport's scan count crosses a milestone (10, 50, 100, 250, 500, 1000, …) — e.g. "your passport was opened 1000 times". Data: { product_id, count, milestone }.

The scan.clone_suspected flags possible counterfeiting: a unique (serialised) passport was scanned unusually often and from many different countries/devices — which may indicate a copied QR code. Data: { product_id, count, countries, unique_devices }.

Delivery

POST https://your-system.example/veridyn-webhook
Content-Type: application/json
X-Veridyn-Event: product.updated
X-Veridyn-Signature: sha256=<hmac>

{
  "event": "product.updated",
  "data": { "id": "a1993ef7-…", "category": "textile", "version_no": 2 },
  "sent_at": "2026-07-02T13:19:11+00:00"
}

Signature verification

The X-Veridyn-Signature is the HMAC-SHA256 of the raw body with the webhook secret (shown in Settings). Verify it — e.g. in PHP:

$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_VERIDYN_SIGNATURE'] ?? '')) {
    http_response_code(401); exit; // invalid signature}

Respond with a 2xx status. If delivery fails (non-2xx / timeout), we automatically retry with exponential backoff (about 1 min → 5 min → 30 min → 2 h → 6 h, up to 6 attempts), giving up on persistent failure. The status of the last delivery is shown in Settings.

💡 The category schemas (which fields are required/optional) are visible on the product form and via the /schema/{category} endpoint. Currently available: textile, battery and furniture. The schema grows as the EU finalises categories.

← Settings / API keys