# Tradeloop DPP API Specification
# ISO 20435 Digital Product Passport System
# Version: 1.0.0
================================================================================
BASE URL
================================================================================
Production: https://inventory-csv-agent.vercel.app
Local: http://localhost:3000
================================================================================
DOCUMENTATION
================================================================================
Interactive API (Swagger UI): /swagger
OpenAPI Specification (JSON): /api/swagger
================================================================================
OVERVIEW
================================================================================
This API implements ISO 20435 for Digital Product Passports (DPPs). Each physical
asset is assigned a Decentralized Identifier (DID) computed from:
DID = SHA-256(manufacturer + partNumber + serialNumber)
The DID is a 64-character uppercase hex string. A human-readable Universal Serial
Number (USN) is derived as base58(DID)[0:12] formatted as xxxx-xxxx-xxxx.
================================================================================
AUTHENTICATION
================================================================================
No authentication required. All endpoints are public.
================================================================================
ENDPOINTS
================================================================================
## CSV Upload (Simplified)
--------------------------------------------------------------------------------
POST /api/did/register
Content-Type: multipart/form-data
Upload a CSV file. System computes hashes and registers DIDs automatically.
Required CSV columns:
- manufacturer Product manufacturer name
- partNumber Manufacturer part number
- serialNumber Unique serial number
Example CSV:
manufacturer,partNumber,serialNumber
NVIDIA,DGXA100,SN-001234567
Apple,iPhone15Pro,IMEI-987654321
Response: Array of registered DIDs with computed hashes.
--------------------------------------------------------------------------------
## Register DID (Advanced)
--------------------------------------------------------------------------------
POST /api/did/register
Content-Type: application/json
Register a single DID with pre-computed hashes.
Request body:
{
"did": "string", // 64-char uppercase hex SHA-256 hash
"dataObjects": [ // Array of data objects
{
"objectType": "string", // e.g., "physicalIdentifiers"
"data": { ... } // Object data
}
],
"hashTree": {
"algorithm": "SHA-256",
"individualHashes": [...], // SHA-256 of each stringified dataObject
"rootHash": "string" // SHA-256 of sorted concatenated hashes
}
}
Response 201:
{
"success": true,
"did": "string",
"usn": "xxxx-xxxx-xxxx"
}
--------------------------------------------------------------------------------
## Resolve DID
--------------------------------------------------------------------------------
GET /api/did/{did}
Retrieve a DID document.
Parameters:
did 64-char hex string or did:pai:xxx format
Response 200:
{
"did": "string",
"usn": "string",
"dataObjects": [...],
"hashTree": {...},
"created_at": "ISO8601",
"updated_at": "ISO8601"
}
Response 404: DID not found
Response 410: DID deactivated (Gone)
--------------------------------------------------------------------------------
## Update DID
--------------------------------------------------------------------------------
POST /api/did/update
Content-Type: application/json
Update an existing DID document. Requires priorRootHash for version tracking.
Request body:
{
"did": "string",
"dataObjects": [...],
"hashTree": {
"algorithm": "SHA-256",
"individualHashes": [...],
"priorRootHash": "string", // Must match current rootHash
"rootHash": "string"
}
}
Response 200: Updated document
Response 400: Hash mismatch
Response 404: DID not found
--------------------------------------------------------------------------------
## Deactivate DID
--------------------------------------------------------------------------------
POST /api/did/deactivate
Content-Type: application/json
Soft-delete a DID. Document preserved for audit trail.
Request body:
{
"did": "string"
}
Response 200: { "success": true, "deactivatedAt": "ISO8601" }
Response 404: DID not found
Response 410: Already deactivated
--------------------------------------------------------------------------------
## List DIDs
--------------------------------------------------------------------------------
GET /api/did/list?limit=50&offset=0&active=true
Query parameters:
limit Number of results (default: 50, max: 100)
offset Pagination offset (default: 0)
active Filter by active status (true/false)
Response 200:
{
"dids": [...],
"total": number,
"limit": number,
"offset": number
}
--------------------------------------------------------------------------------
## Compute Hash Tree
--------------------------------------------------------------------------------
POST /api/compute-hash-tree
Content-Type: application/json
Utility endpoint to compute DID, USN, and hash tree from data objects.
Request body:
{
"dataObjects": [
{
"objectType": "physicalIdentifiers",
"data": {
"manufacturer": "NVIDIA",
"partNumber": "DGXA100",
"serialNumber": "SN-001"
}
}
],
"priorRootHash": null // Optional, for updates
}
Response 200:
{
"did": "string",
"usn": "xxxx-xxxx-xxxx",
"hashTree": {
"algorithm": "SHA-256",
"individualHashes": [...],
"rootHash": "string"
}
}
--------------------------------------------------------------------------------
## Verify Hash Tree
--------------------------------------------------------------------------------
POST /api/verify-hash-tree
Content-Type: application/json
Verify that a hash tree matches its data objects.
Request body:
{
"dataObjects": [...],
"hashTree": {...}
}
Response 200: { "valid": true }
Response 400: { "valid": false, "errors": [...] }
--------------------------------------------------------------------------------
## File Upload
--------------------------------------------------------------------------------
POST /api/storage/upload
Content-Type: multipart/form-data
Upload a file attachment for a DID.
Form fields:
file The file to upload
did Associated DID (64-char hex)
Response 200:
{
"success": true,
"url": "https://..."
}
================================================================================
HASH COMPUTATION (ISO 20435 Section 7)
================================================================================
1. Individual Hash:
hash = SHA-256(JSON.stringify(dataObject))
2. Root Hash:
sortedHashes = individualHashes.sort()
concatenated = priorRootHash + sortedHashes.join('')
rootHash = SHA-256(concatenated)
3. DID Generation:
physicalIdentifiers = { manufacturer, partNumber, serialNumber }
did = SHA-256(manufacturer + partNumber + serialNumber).toUpperCase()
4. USN Generation:
bytes = hexToBytes(did)
usn = base58(bytes).slice(0, 12)
formatted = usn.slice(0,4) + '-' + usn.slice(4,8) + '-' + usn.slice(8,12)
================================================================================
ERROR RESPONSES
================================================================================
400 Bad Request Invalid input, missing required fields, hash mismatch
404 Not Found DID does not exist
410 Gone DID has been deactivated
500 Server Error Internal error
All errors return:
{
"error": "string",
"details": "string" // Optional
}
================================================================================
LINKS
================================================================================
Swagger UI: /swagger
OpenAPI JSON: /api/swagger
Upload Interface: /dpp/upload
View DPPs: /dpp/list-2
================================================================================