DXA Blockchain API
Layer-3 attestation hub — anchor, verify & revoke on-chain
DXA Blockchain is a Layer-3 attestation hub: anchor a data fingerprint on the ledger, verify its integrity later, and revoke it when needed. Data is canonicalized (canonical JSON, NFC-normalized) then keccak256-hashed; only the fingerprint is stored, never the raw data. Records are bound to an issuer via an EIP-191 signature and governed by a signer-authorization contract.
Base URL
Authentication
The public sandbox runs in `mock` mode (simulated tx/hash, no wallet needed). The on-chain build (Base Sepolia) signs with a relayer key stored in a Cloudflare secret — no keys on the client; only an authorized issuer can anchor/revoke. Rate limit ~5 req/min/IP recommended.
Attestation ledger
/api/anchor Anchor a data fingerprint on the ledger
Auth: None (public sandbox)
Body parameters
| Field | Type | Description |
|---|---|---|
scenario* | 'e_invoice' | 'fund_disbursal' | 'kyc_profile' | 'academic_credential' | Business scenario type |
payloadId* | string | Business identifier (≤200 chars), e.g. `INV-2026-001` |
dataFields* | object | Key-value data fields to anchor (≤50 keys) |
nonce | number | Replay-protection nonce (defaults to now) |
Example request
curl -X POST 'https://blockchain.dxa.io.vn/api/anchor' \
-H 'Content-Type: application/json' \
-d '{
"scenario": "e_invoice",
"payloadId": "INV-2026-001",
"dataFields": { "taxId": "0312345678", "amount": 500000000, "issuedAt": "2026-05-30" }
}' Example response
{
"success": true,
"mode": "onchain",
"dataHash": "0x9af1…c20b",
"payloadType": "e_invoice",
"payloadId": "INV-2026-001",
"nonce": 1769990400000,
"transactionHash": "0x4e8d…7a31",
"blockNumber": 14523456,
"timestamp": 1769990400,
"issuerId": "0x71C…e3F2",
"status": 1,
"explorerUrl": "https://sepolia.basescan.org/tx/0x4e8d…7a31"
} Error codes
400 | Validation failed / unknown scenario / payload too large |
409 already_anchored | Fingerprint already anchored |
/api/verify Verify data against the anchored record (supports a QR sealCode)
Auth: None (public sandbox)
Body parameters
| Field | Type | Description |
|---|---|---|
dataFields* | object | Data to check (re-hashed & matched) |
sealCode | string | A bytes32 seal code (0x…) from a QR — checked separately if it differs from dataHash |
Example request
curl -X POST 'https://blockchain.dxa.io.vn/api/verify' \
-H 'Content-Type: application/json' \
-d '{ "dataFields": { "taxId": "0312345678", "amount": 500000000, "issuedAt": "2026-05-30" } }' Example response
{
"success": true,
"mode": "onchain",
"dataHash": "0x9af1…c20b",
"onChain": true,
"sealCodeOnChain": null,
"status": 1,
"payloadType": "e_invoice",
"issuerId": "0x71C…e3F2",
"timestamp": 1769990400
} /api/revoke Revoke (deactivate) an attestation record
Auth: Original issuer (signs in on-chain mode)
Body parameters
| Field | Type | Description |
|---|---|---|
sealCode | string | The bytes32 seal code to revoke (or use `dataFields`) |
dataFields | object | Data to derive the sealCode (if `sealCode` is omitted) |
Example response
{
"success": true,
"mode": "onchain",
"dataHash": "0x9af1…c20b",
"status": 2,
"transactionHash": "0x77a…b91",
"explorerUrl": "https://sepolia.basescan.org/tx/0x77a…b91"
} Error codes
403 forbidden | Only the original issuer can revoke |
404 not_found | Record not found |
409 already_revoked | Record already revoked |
/api/trustway Trustway gateway — sign an AI result (EIP-191) then anchor it
Auth: None (reference integration; signs with the relayer key)
Body parameters
| Field | Type | Description |
|---|---|---|
score | number | AI score/result (default 785) |
payloadId | string | Document/request ID |
source | string | Source system (default `DXA_TRUSTWAY_GATEWAY`) |
anchor | boolean | Whether to anchor the result (default true) |
Example response
{
"success": true,
"mode": "onchain",
"payloadType": "TRUSTWAY_AI_SCORE",
"securePayload": { "source": "DXA_TRUSTWAY_GATEWAY", "timestamp": 1769990400, "score": 785, "payloadId": "DOC-001" },
"dataHash": "0x…",
"nonce": 1769990400000,
"sig": { "v": 27, "r": "0x…", "s": "0x…" },
"anchored": { "transactionHash": "0x…", "explorerUrl": "https://sepolia.basescan.org/tx/0x…" }
} Smart contracts (Base Sepolia)
DXAAttestationRegistry.sol Attestation registry — EIP-191 signed, anchor & revoke, nonce replay-protection
Auth: Authorized issuer signature
Interface
// Solidity — DXAAttestationRegistry
function verifyAndAnchor(
bytes32 _dataHash, string _payloadType, uint256 _nonce,
uint8 _v, bytes32 _r, bytes32 _s) external; // xác thực chữ ký & ghi
function revokeAttestation(bytes32 _dataHash) external; // thu hồi (chỉ issuer gốc)
function getRecord(bytes32 _dataHash) external view
returns (bytes32, string, uint256, address, uint8); // đọc bản ghi (status 1=Active, 2=Revoked)
function isAnchored(bytes32 _dataHash) external view returns (bool);
// event DataAnchored(bytes32 indexed dataHash, string payloadType, address indexed issuerId, uint256 timestamp)
// event DataRevoked(bytes32 indexed dataHash, address indexed revokerId) DXAGovernanceSigners.sol Issuer authorization per payload type (admin-managed)
Auth: Contract admin
Interface
// Solidity — DXAGovernanceSigners
function setSignerStatus(address _signer, string _payloadType, bool _status) external; // onlyAdmin
function isSignerAuthorized(address _signer, string _payloadType) external view returns (bool);
function transferAdmin(address _newAdmin) external; // onlyAdmin