QXMP Oracle
Integration Guide
Fetch real-world asset data via the public REST API or directly from on-chain smart contracts. Managing $1.1 trillion in tokenized assets with verifiable proofs.
Public REST API • No Auth Required • JavaScript / Python / curl Examples • On-Chain Proof-of-Reserve
Custom Oracle Infrastructure
QXMP has built a custom oracle system (not RedStone or Chainlink) for providing real-world asset valuations on-chain. Unlike traditional oracles that rely on third-party data providers, QXMP maintains full sovereignty over data verification, timing, and quality assurance.
Recommended: Use the REST API
The QXMP Oracle API (api.qxmp.ai) reads from the on-chain smart contracts and enriches raw data with human-readable names, types, jurisdictions, and proof-of-reserve validation status. You do NOT need to interact with the smart contracts directly — the API does this for you. See the REST API section below.
Design Philosophy
Data Sovereignty: Complete control over data sources, validation logic, and submission timing
Cryptographic Verification: Every data point cryptographically signed and verifiable on-chain via ECDSA
Complete Auditability: Full historical trail of all valuations with immutable timestamps
8 Decimal Precision
USD values stored with 8 decimal places for accuracy
EIP-191 Standard
Ethereum-standard signature format for compatibility
Staleness Protection
24-hour default freshness requirement prevents replay attacks
Soft Delete Support
Data preservation for regulatory compliance
Dynamic Fields
Unlimited metadata fields per asset with schema versioning
12 Assets Live
Managing $1.1 trillion across mining & resource projects
QXMP Oracle REST API
The QXMP Oracle REST API is a public, unauthenticated JSON API that provides enriched RWA asset data sourced from three verified smart contracts on the QELT blockchain. This is the recommended integration method for most developers.
| Base URL | https://api.qxmp.ai/api/v1/rwa |
| Protocol | HTTPS (JSON REST) |
| Authentication | None required — Public API |
| Rate Limiting | Returns HTTP 429 with Retry-After header when exceeded |
| CORS | Enabled — call directly from any browser |
| Response Format | All responses wrapped in { success: true, data: { ... } } |
Architecture Overview
┌──────────────┐ HTTPS ┌──────────────────────┐ reads from ┌────────────────────┐
│ Your App / │ ──────────────▶│ QXMP Oracle REST API │ ◀───────────────── │ QELT Blockchain │
│ Any Client │ (JSON REST) │ api.qxmp.ai │ │ (EVM L1) │
└──────────────┘ └──────────────────────┘ └────────────────────┘
│
│ reads from 3 smart contracts:
│ • QXMPDynamicRegistryV2
│ • QXMPProofOfReserveV3
│ • QXMPOracleController
└──────────────────────────────────────────┘API Endpoints
/healthCheck if the Oracle API and blockchain connection are healthy.
GET https://api.qxmp.ai/api/v1/rwa/health
Response:
{
"success": true,
"status": "healthy",
"blockchain": { ... },
"timestamp": "2026-02-11T10:00:00.000Z"
}/assetsMain EndpointFetch all RWA assets with valuations, proof status, and on-chain data. This is the primary endpoint most developers need.
| Param | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number |
limit | number | 50 | Items per page (max: 100) |
GET https://api.qxmp.ai/api/v1/rwa/assets?page=1&limit=100
Response:
{
"success": true,
"data": {
"assets": [
{
"assetCode": "QXMP:RHENO-JORC-ZA",
"name": "Rhenosterspruit / Syferfontein Mining Project",
"type": "Rare Earth Elements",
"jurisdiction": "ZA",
"valueUSD": "113989838841.85",
"status": "registered",
"holder": "0x...",
"assetCodeHash": "0x...",
"txHash": "0x...",
"registeredAt": "2025-06-15T...",
"updatedAt": "2026-02-10T...",
"onChain": {
"registryValue": "113989838841.85",
"holder": "0x...",
"registeredAt": "2025-06-15T...",
"lastUpdated": "2026-02-10T..."
},
"latestProof": {
"valueUSD": "113989838841.85",
"timestamp": "2026-02-10T12:00:00.000Z",
"ageHours": "23.5",
"isFresh": true,
"submitter": "0x..."
},
"proofHistory": [
{
"valueUSD": "113989838841.85",
"timestamp": "2026-02-10T12:00:00.000Z"
}
]
}
],
"pagination": { "page": 1, "limit": 100, "total": 12, "totalPages": 1 },
"summary": { "count": 12, "totalValue": "1090958787645.94", "currency": "USD" }
}
}Key Fields per Asset
| Field | Type | Description |
|---|---|---|
assetCode | string | Unique identifier, e.g. "QXMP:RHENO-JORC-ZA" |
name | string | Human-readable name of the asset |
type | string | Category: "Gold", "Diamond", "Rare Earth Elements", "Heavy Mineral Sands", "Nickel and Cobalt" |
jurisdiction | string | Country code: "ZA", "NA", "MZ", "LR", "AU" |
valueUSD | string | USD valuation — parse with parseFloat() |
latestProof | object | Most recent oracle proof-of-reserve submission |
latestProof.isFresh | boolean | true if proof is less than 24 hours old |
latestProof.ageHours | string | Hours since proof was submitted |
proofHistory | array | Historical proof submissions |
/assets/{assetCode}Get full details for a single asset including complete on-chain data and proof history.
GET https://api.qxmp.ai/api/v1/rwa/assets/QXMP:RHENO-JORC-ZA Returns the same asset object shape as above, with full onChain data and proofHistory.
/statsGet portfolio-level statistics: total value, average value, breakdowns by asset type and jurisdiction.
GET https://api.qxmp.ai/api/v1/rwa/stats
Response:
{
"success": true,
"data": {
"totalAssets": 12,
"totalValue": "1090958787645.94",
"averageValue": "90913232303.83",
"currency": "USD",
"byType": [
{ "type": "Rare Earth Elements", "count": 3, "value": "504758269067.14", "percentage": "46.27" },
{ "type": "Gold", "count": 2, "value": "198234567890.12", "percentage": "18.17" }
],
"byJurisdiction": [
{ "jurisdiction": "ZA", "count": 8, "value": "783302841350.92", "percentage": "71.80" },
{ "jurisdiction": "NA", "count": 2, "value": "156789012345.67", "percentage": "14.37" }
]
}
}Fetch RWA Data — Code Examples
Copy-paste examples to start fetching RWA asset data immediately. No authentication, no API keys, no setup.
JavaScript / TypeScript
Works in any browser, Node.js, React, Next.js, Vue, or any JavaScript framework.
// Base URL for the QXMP Oracle API
const API_BASE = 'https://api.qxmp.ai/api/v1/rwa';
// ─── Get all RWA assets ───────────────────────────────
async function getAllAssets(page = 1, limit = 100) {
const response = await fetch(
`${API_BASE}/assets?page=${page}&limit=${limit}`
);
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'API request failed');
}
// Parse string values to numbers for display
const assets = result.data.assets.map(asset => ({
...asset,
valueUSD: parseFloat(asset.valueUSD),
registeredAt: new Date(asset.registeredAt),
updatedAt: new Date(asset.updatedAt),
latestProof: asset.latestProof ? {
...asset.latestProof,
valueUSD: parseFloat(asset.latestProof.valueUSD),
timestamp: new Date(asset.latestProof.timestamp),
ageHours: parseFloat(asset.latestProof.ageHours)
} : null
}));
return {
assets,
pagination: result.data.pagination,
summary: {
count: result.data.summary.count,
totalValue: parseFloat(result.data.summary.totalValue),
currency: result.data.summary.currency
}
};
}
// ─── Get portfolio statistics ─────────────────────────
async function getPortfolioStats() {
const response = await fetch(`${API_BASE}/stats`);
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'API request failed');
}
return {
totalAssets: result.data.totalAssets,
totalValue: parseFloat(result.data.totalValue),
averageValue: parseFloat(result.data.averageValue),
currency: result.data.currency,
byType: result.data.byType.map(item => ({
type: item.type,
count: item.count,
value: parseFloat(item.value),
percentage: parseFloat(item.percentage)
})),
byJurisdiction: result.data.byJurisdiction.map(item => ({
jurisdiction: item.jurisdiction,
count: item.count,
value: parseFloat(item.value),
percentage: parseFloat(item.percentage)
}))
};
}
// ─── Get a single asset with full details ─────────────
async function getAsset(assetCode) {
const response = await fetch(
`${API_BASE}/assets/${assetCode}`
);
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'API request failed');
}
return result.data;
}
// ─── Check API health ─────────────────────────────────
async function checkHealth() {
const response = await fetch(`${API_BASE}/health`);
return await response.json();
}
// ─── Example usage ────────────────────────────────────
const data = await getAllAssets();
console.log(`Total: ${data.summary.count} assets worth $${data.summary.totalValue.toLocaleString()}`);
for (const asset of data.assets) {
const proof = asset.latestProof?.isFresh ? '✅ Fresh' : '⚠️ Stale';
console.log(` ${asset.assetCode}: $${asset.valueUSD.toLocaleString()} [${proof}]`);
}curl (Quick Testing)
Test the API from your terminal in seconds.
# Get all assets curl -s "https://api.qxmp.ai/api/v1/rwa/assets?page=1&limit=100" | jq . # Get portfolio stats curl -s "https://api.qxmp.ai/api/v1/rwa/stats" | jq . # Get a specific asset by code curl -s "https://api.qxmp.ai/api/v1/rwa/assets/QXMP:RHENO-JORC-ZA" | jq . # Health check curl -s "https://api.qxmp.ai/api/v1/rwa/health" | jq .
Python
Using the requests library.
import requests
API_BASE = "https://api.qxmp.ai/api/v1/rwa"
def get_all_assets(page=1, limit=100):
response = requests.get(f"{API_BASE}/assets", params={"page": page, "limit": limit})
data = response.json()
if not data.get("success"):
raise Exception(data.get("error", "API request failed"))
return data["data"]
def get_portfolio_stats():
response = requests.get(f"{API_BASE}/stats")
data = response.json()
if not data.get("success"):
raise Exception(data.get("error", "API request failed"))
return data["data"]
def get_asset(asset_code):
response = requests.get(f"{API_BASE}/assets/{asset_code}")
data = response.json()
if not data.get("success"):
raise Exception(data.get("error", "API request failed"))
return data["data"]
# ─── Example usage ─────────────────────────────────────
assets_data = get_all_assets()
print(f"Total assets: {assets_data['summary']['count']}")
print(f"Total value: ${float(assets_data['summary']['totalValue']):,.2f}")
for asset in assets_data["assets"]:
proof_status = "✅ Fresh" if asset.get("latestProof", {}).get("isFresh") else "⚠️ Stale/None"
print(f" {asset['assetCode']}: ${float(asset['valueUSD']):,.2f} [{proof_status}]")Quick Start Summary
GET /assets?page=1&limit=100 — All assets with valuations, proof status, and on-chain data
GET /stats — Portfolio-level statistics (total value, breakdowns by type/jurisdiction)
GET /assets/{assetCode} — Full detail for a single asset including proof history
GET /health — API and blockchain connection health status
No authentication required. All responses are JSON. Parse valueUSD fields with parseFloat() as they come as strings.
Rate Limiting & Caching
Rate Limiting
- •API returns HTTP 429 when rate limited
- •
Retry-Afterheader contains wait time in seconds - •Implement exponential backoff with 3 retries
- •Deduplicate in-flight requests to the same endpoint
Recommended Caching
- •Cache responses for at least 60 seconds
- •Oracle proofs update ~once per day, so data is stable
- •A 2–5 minute cache is ideal for display purposes
- •Auto-refresh every 60s for live dashboards
Example: Retry with Backoff (JavaScript)
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
const response = await fetch(url);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '5');
console.warn(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
}
throw new Error('Max retries exceeded');
}Asset Data Reference
Asset Types
| Type | Description |
|---|---|
Gold | Gold mining concessions and reserves |
Diamond | Diamond mining reserves |
Rare Earth Elements | Rare earth mining projects |
Heavy Mineral Sands | Heavy mineral sand operations |
Nickel and Cobalt | Nickel and cobalt operations |
Jurisdictions
| Code | Country |
|---|---|
ZA | South Africa |
NA | Namibia |
MZ | Mozambique |
LR | Liberia |
AU | Australia |
Proof Freshness
isFresh === true — proof is less than 24 hours old
isFresh === false — proof is older than 24 hours
ageHours — exact hours since proof submission
Smart Contracts (On-Chain)
Three core smart contracts work together to provide secure, verifiable asset pricing data on the QELT blockchain. Deployed on January 12, 2026, by deployer wallet 0xBd6C978C38b0954e1153fB9892f007611726E2B0. The REST API reads from these contracts — most developers won't need to interact with them directly.
QXMPOracleController
Manages authorized signers and verifies oracle signatures using ECDSA cryptography
0xB2a332dE80923134393306808Fc2CFF330de03bAView on ExplorerQXMPProofOfReserveV3
Submits and stores proof submissions with complete audit trail. Owns Registry contract for automatic value updates.
0x6123287acBf0518E0bD7F79eAcAaFa953e10a768View on ExplorerQXMPDynamicRegistryV2
Universal key-value storage for asset data with soft delete support. Schema-less design supports any asset type.
0xd00cD3a986746cf134756464Cb9Eaf024DF110fBView on ExplorerOwnership Architecture
ProofOfReserve V3 owns Registry V2, allowing automatic value updates when new oracle proofs are submitted. The deployer wallet owns ProofOfReserve for administrative operations.
System Architecture
Three-layer architecture ensures maximum security, flexibility, and separation of concerns
1Controller Layer: Signature Verification
OracleController manages authorized signers and validates ECDSA signatures using EIP-191 standard. Configurable staleness thresholds (24h default) and value bounds provide anomaly detection.
verifySignature()ECDSA validation
addSigner()Manage signers
isSigner()Check authorization
2Proof Layer: Audit Trail & Submission
ProofOfReserveV3 stores oracle-verified proofs with complete audit trails. Each proof includes value, timestamp, block number, and signer address for full transparency. Owns Registry for automatic updates.
submitProofWithSignature()Store verified proof
getLatestProof()Query latest data
getProofHistory()Historical records
3Registry Layer: Asset Storage
DynamicRegistryV2 stores asset metadata with schema-less dynamic fields. Supports ANY asset type - gold, platinum, lithium, uranium, diamonds, and more. Unlimited custom fields per asset.
getAsset()Core asset data
getAssetFields()Dynamic metadata
updatePrimaryValue()Update valuations
Oracle Mechanism
Understanding how asset codes, signatures, and proofs work together
Asset Code Generation
Asset codes use Keccak-256 hashing for deterministic identifiers
// Format: QXMP:{PROJECT}-{STD}-{COUNTRY}
const assetCode = ethers.utils.id(
'QXMP:ATKA2-NI43-ZA'
);
// Result: 0x4f8b... (bytes32 hash)Value Encoding
USD values stored with 8 decimal precision
const valueUsd = 125000000.50; // $125M const encoded = ethers.utils.parseUnits( valueUsd.toString(), 8 ); // Result: 12500000050000000
Signature Generation
ECDSA signatures with EIP-191 standard
// 1. Create message hash const hash = ethers.utils.solidityKeccak256( ['bytes32', 'bytes32', 'uint256', 'uint256'], [assetCode, dataFeedId, value, timestamp] ); // 2. Sign with private key const sig = await signer.signMessage( ethers.utils.arrayify(hash) );
On-Chain Verification
Contract verifies signature and stores proof
// Verify signature address signer = controller.verifySignature( messageHash, signature ); require( controller.isSigner(signer), "Invalid signer" ); // Store proof & update registry
On-Chain Quick Start (Advanced)
Note: Most developers should use the REST API above instead of reading smart contracts directly. The on-chain approach below is for advanced use cases where you need to verify data directly on the blockchain without trusting the API layer.
Integrate with QXMP Oracle smart contracts in 4 steps using ethers.js
Install Dependencies
Add ethers.js to your project
npm install ethers@5.7.2
Connect to QELT Blockchain
Initialize provider and contract instances
const { ethers } = require('ethers');
// Connect to QELT
const provider = new ethers.providers.JsonRpcProvider(
'https://mainnet.qelt.ai'
);
// Contract addresses
const REGISTRY = '0xd00cD3a986746cf134756464Cb9Eaf024DF110fB';
const PROOF_OF_RESERVE = '0x6123287acBf0518E0bD7F79eAcAaFa953e10a768';
const CONTROLLER = '0xB2a332dE80923134393306808Fc2CFF330de03bA';Query Asset Data
Read asset information from Registry
// Load Registry contract
const registry = new ethers.Contract(
REGISTRY,
REGISTRY_ABI,
provider
);
// Generate asset code
const assetCode = ethers.utils.id('QXMP:ATKA2-NI43-ZA');
// Get asset data
const asset = await registry.getAsset(assetCode);
console.log('Name:', asset.assetName);
console.log('Type:', asset.assetType);
console.log('Value:', ethers.utils.formatUnits(asset.primaryValueUsd, 8));Get Latest Proof
Query oracle proofs with timestamps
// Load Proof of Reserve contract
const proofOfReserve = new ethers.Contract(
PROOF_OF_RESERVE,
PROOF_OF_RESERVE_ABI,
provider
);
// Get latest proof
const dataFeedId = ethers.utils.id('QXMP:ATKA2-NI43-ZA-FULL');
const proof = await proofOfReserve.getLatestProof(
assetCode,
dataFeedId
);
console.log('Value:', ethers.utils.formatUnits(proof.value, 8), 'USD');
console.log('Timestamp:', new Date(proof.timestamp * 1000).toISOString());
console.log('Submitter:', proof.submitter);Network Information
Deployed & Operational on QELT Blockchain
All contracts deployed January 12, 2026, and fully operational. Query real asset data and oracle proofs directly from the blockchain.
Security Features
ECDSA Signature Verification
Every proof cryptographically signed using secp256k1 elliptic curve (same as Ethereum wallets). Unforgeability guaranteed without private key access.
- • EIP-191 compliant signature format
- • 65-byte signatures (r, s, v components)
- • On-chain ecrecover verification
Staleness Protection
24-hour default freshness requirement prevents replay attacks and ensures data currency. Configurable threshold per deployment.
- • Automatic timestamp validation
- • Prevents old proof resubmission
- • Ensures up-to-date valuations
Immutable Audit Trail
Complete proof history permanently stored on QELT blockchain. No functions to modify or delete existing records - only soft delete for fields.
- • Block-level precision timestamps
- • Event logs for off-chain indexing
- • Transparent transaction history
Access Control
Only authorized signers can submit valid proofs. Multi-level access control with owner-only administrative functions.
- • Signer whitelist management
- • Owner-only configuration updates
- • Public read access for transparency
Registered Assets
Currently managing 12 tokenized mining and resource projects across multiple jurisdictions
| Asset Code | Name | Type | Standard | Jurisdiction |
|---|---|---|---|---|
ATKA2-NI43-ZA | Atka Platinum Project | Platinum | NI 43-101 | South Africa |
GOLD1-NI43-ZA | Gold Reserve 1 | Gold | NI 43-101 | South Africa |
LITH3-JORC-AU | Lithium Deposit 3 | Lithium | JORC | Australia |
URANIUM9-JORC-NA | Uranium Deposit 9 | Uranium | JORC | Namibia |
DIAMOND10-NI43-BW | Diamond Mine 10 | Diamonds | NI 43-101 | Botswana |
And 7 additional assets spanning copper, silver, nickel, zinc, cobalt, and rare earth elements
Why QXMP Oracle?
Data Sovereignty
QXMP maintains complete control over data sources, validation logic, and submission timing. No dependency on third-party oracle providers like Chainlink or RedStone.
Cryptographic Proofs
Every data point cryptographically signed with ECDSA and verified on-chain. Immutable audit trail with block-level precision for regulatory compliance.
Universal Asset Support
Schema-less dynamic field system supports ANY asset type with unlimited custom metadata. Perfect for diverse RWA portfolios.
Low Cost & Fast
Deployed on QELT blockchain with ~$0.002 per transaction and 3-second block times. Sub-second proof submission when market conditions change.
Ready to Integrate QXMP Oracle?
Start fetching RWA data in minutes with the public REST API. No authentication required. Or go deeper with direct on-chain smart contract access.
