API Reference

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

https://blockchain.dxa.io.vn

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

POST /api/anchor

Anchor a data fingerprint on the ledger

Auth: None (public sandbox)

Body parameters

FieldTypeDescription
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" }
  }'
const res = await fetch('https://blockchain.dxa.io.vn/api/anchor', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    scenario: 'e_invoice',
    payloadId: 'INV-2026-001',
    dataFields: { taxId: '0312345678', amount: 500_000_000, issuedAt: '2026-05-30' },
  }),
});
const { dataHash, explorerUrl } = await res.json();

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

400Validation failed / unknown scenario / payload too large
409 already_anchoredFingerprint already anchored
POST /api/verify

Verify data against the anchored record (supports a QR sealCode)

Auth: None (public sandbox)

Body parameters

FieldTypeDescription
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
}
POST /api/revoke

Revoke (deactivate) an attestation record

Auth: Original issuer (signs in on-chain mode)

Body parameters

FieldTypeDescription
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 forbiddenOnly the original issuer can revoke
404 not_foundRecord not found
409 already_revokedRecord already revoked
POST /api/trustway

Trustway gateway — sign an AI result (EIP-191) then anchor it

Auth: None (reference integration; signs with the relayer key)

Body parameters

FieldTypeDescription
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