π Analytics & Reports Implementation Guides
Comprehensive developer guide for implementing business intelligence, compliance reporting, and data analytics capabilities.
π Quick Navigation
π― Getting Started
New to Analytics Reports? Start here to get up and running quickly.
β¨ Best Practices
Learn recommended patterns and industry best practices.
π§ Advanced Topics
Deep dives into advanced features and capabilities.
π― API Overview & Architecture
Business Purpose
The Analytics & Reports API serves as the comprehensive business intelligence backbone for Quub Exchange, providing:
- Automated Compliance Reporting: Generate regulatory-compliant reports for various jurisdictions
- Real-time Business Intelligence: Live dashboards with KPIs and performance metrics
- Financial Analytics: Investment performance, ROI analysis, and distribution tracking
- Multi-format Data Export: PDF, CSV, JSON, and XML output formats
- Audit Trail Management: Complete transaction and activity reporting
Technical Architecture
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Client App β β Analytics API β β Data Sources β
β ββββββ ββββββ β
β β’ Dashboards β β β’ Report Engine β β β’ Trading Data β
β β’ Reports UI β β β’ Analytics β β β’ User Data β
β β’ Export Tools β β β’ Compliance β β β’ Market Data β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β
βββββββββββββββββββ
β Data Pipeline β
β β
β β’ ETL Process β
β β’ Aggregation β
β β’ Caching β
βββββββββββββββββββ
Core Data Models
Statements: Account and distribution statements for specific periods Tax Reports: Annual tax filings with jurisdiction-specific formatting Regulatory Reports: Compliance disclosures (AML, KYC, AUDIT, COMPLIANCE) Analytics Dashboard: Real-time KPIs and performance metrics
π― Quick Start
Prerequisites
Before you begin, ensure you have:
- β Active Quub Exchange account with analytics permissions
- β
API credentials with
analytics:readscope (andanalytics:writefor report generation) - β Development environment configured (Node.js 18+ or Python 3.9+)
- β Understanding of JWT authentication and financial data handling
5-Minute Setup
Step 1: Install SDK
Node.js:
npm install @quub/analytics-sdk axios
Python:
pip install quub-analytics requests
Step 2: Configure Authentication
Node.js:
import { AnalyticsClient } from "@quub/analytics-sdk";
const client = new AnalyticsClient({
apiKey: process.env.QUUB_API_KEY,
orgId: process.env.QUUB_ORG_ID,
baseUrl:
process.env.NODE_ENV === "production"
? "https://api.quub.exchange/v2"
: "https://sandbox.quub.exchange/v2",
});
Python:
from quub.analytics import AnalyticsClient
import os
client = AnalyticsClient(
api_key=os.getenv('QUUB_API_KEY'),
org_id=os.getenv('QUUB_ORG_ID'),
base_url='https://sandbox.quub.exchange/v2' # or production URL
)
Step 3: Fetch Your First Analytics Dashboard
Node.js:
// GET /orgs/{orgId}/analytics/dashboard
const dashboard = await client.get(
`/orgs/${client.orgId}/analytics/dashboard`,
{
params: {
period: "MONTHLY",
startDate: "2025-01-01",
endDate: "2025-01-31",
},
}
);
console.log("Dashboard Data:", {
totalInvested: dashboard.data.totalInvested,
activeInvestors: dashboard.data.activeInvestors,
roiYTD: dashboard.data.roiYTD,
});
Python:
# GET /orgs/{orgId}/analytics/dashboard
response = client.get(f'/orgs/{client.org_id}/analytics/dashboard', params={
'period': 'MONTHLY',
'startDate': '2025-01-01',
'endDate': '2025-01-31'
})
dashboard = response.json()
print(f"Total Invested: ${dashboard['totalInvested']:,.2f}")
print(f"Active Investors: {dashboard['activeInvestors']}")
print(f"ROI YTD: {dashboard['roiYTD']}%")
Step 4: Retrieve Statements
Node.js:
// GET /orgs/{orgId}/reports/statements
const statements = await client.get(
`/orgs/${client.orgId}/reports/statements`,
{
params: {
limit: 10,
cursor: null, // Start from beginning
},
}
);
// Access statement details
statements.data.data.forEach((statement) => {
console.log(`Statement ID: ${statement.id}`);
console.log(`Period: ${statement.period}`);
console.log(`Format: ${statement.format}`);
console.log(`Download URI: ${statement.uri}`);
});
Python:
# GET /orgs/{orgId}/reports/statements
response = client.get(f'/orgs/{client.org_id}/reports/statements', params={
'limit': 10
})
statements = response.json()
for statement in statements['data']:
print(f"Statement ID: {statement['id']}")
print(f"Period: {statement['period']}")
print(f"Format: {statement['format']}")
print(f"Download URI: {statement['uri']}")
statements = client.reports.get_statements(
limit=10,
period='2025-Q1'
)
# Download a specific statement
if statements['data']:
statement = statements['data'][0]
if statement['uri']:
report_data = client.reports.download(statement['uri'])
print(f"Downloaded {statement['format']} statement for {statement['period']}")
π Core API Operations
1. Statements Management
Business Use Case: Generate and retrieve account statements for specific periods
List Statements
// Get all statements for Q1 2025
const statements = await client.reports.getStatements({
cursor: null, // Start from beginning
limit: 50, // Max 50 results
});
console.log(`Found ${statements.data.length} statements`);
statements.data.forEach((statement) => {
console.log(
`${statement.period}: ${statement.format} (${statement.generatedAt})`
);
});
Implementation Notes:
- Use cursor-based pagination for large result sets
- Statements are generated automatically for each period
- Multiple formats available: PDF (human-readable), CSV (data analysis), JSON (API consumption)
- URI field provides direct download link when report is ready
2. Tax Reports Generation
Business Use Case: Generate jurisdiction-specific tax reports for compliance
Generate Tax Report
// Generate US tax report for 2024
const taxReport = await client.reports.getTaxReport({
year: 2024,
locale: "en", // Localization: en, ar, fr
});
if (taxReport.uri) {
console.log(
`Tax report ready: ${taxReport.format} for ${taxReport.jurisdiction}`
);
// Download the report
const reportBuffer = await client.reports.download(taxReport.uri);
} else {
console.log("Tax report is being generated...");
}
Python Implementation:
# Generate tax report with error handling
try:
tax_report = client.reports.get_tax_report(
year=2024,
locale='en'
)
if tax_report['uri']:
print(f"Tax report ready for {tax_report['jurisdiction']}")
# Process the report
report_data = client.reports.download(tax_report['uri'])
else:
print("Report generation in progress")
except Exception as e:
print(f"Tax report generation failed: {e}")
Implementation Notes:
- Tax reports support multiple jurisdictions (US, EU, etc.)
- Available formats: PDF (filing), XML (electronic submission), JSON (data processing)
- Localization affects date formats, currency symbols, and regulatory text
- Reports include realized gains/losses, trading volume, and fee summaries
3. Regulatory Reports Access
Business Use Case: Access compliance reports for audit and regulatory requirements
List Regulatory Reports
// Get all compliance reports by category
const regulatoryReports = await client.reports.getRegulatoryReports({
category: "AML", // Filter by: AML, KYC, AUDIT, COMPLIANCE
limit: 25,
});
regulatoryReports.data.forEach((report) => {
console.log(`${report.title} (${report.category}) - ${report.issuedAt}`);
});
Compliance Report Categories:
- AML: Anti-Money Laundering reports and suspicious activity
- KYC: Know Your Customer verification and updates
- AUDIT: Financial audits and reconciliation reports
- COMPLIANCE: General regulatory compliance documentation
4. Real-time Analytics Dashboard
Business Use Case: Build live dashboards with KPIs and performance metrics
Get Dashboard Data
// Fetch comprehensive dashboard for current quarter
const dashboard = await client.analytics.getDashboard({
period: "QUARTERLY",
startDate: "2025-01-01",
endDate: "2025-03-31",
});
// Display key metrics
const metrics = {
totalInvested: dashboard.totalInvested,
activeInvestors: dashboard.activeInvestors,
distributionsYTD: dashboard.distributionsYTD,
roiYTD: dashboard.roiYTD,
projectsByStatus: dashboard.projectsByStatus,
};
console.log("Dashboard Metrics:", metrics);
Advanced Dashboard Implementation
class AnalyticsDashboard:
def __init__(self, client, org_id):
self.client = client
self.org_id = org_id
async def get_performance_metrics(self, period='MONTHLY'):
"""Fetch and calculate performance metrics"""
dashboard = await self.client.analytics.get_dashboard(
period=period,
start_date=self.get_period_start(period),
end_date=self.get_period_end(period)
)
return {
'total_invested': dashboard['totalInvested'],
'active_investors': dashboard['activeInvestors'],
'roi_ytd': dashboard['roiYTD'],
'distributions_ytd': dashboard['distributionsYTD'],
'project_breakdown': dashboard['projectsByStatus']
}
def calculate_growth_rate(self, current, previous):
"""Calculate period-over-period growth"""
if previous == 0:
return 0
return ((current - previous) / previous) * 100
Dashboard Period Options:
- DAILY: Day-by-day analytics for operational monitoring
- WEEKLY: Week-over-week trends and patterns
- MONTHLY: Monthly performance and investor reporting
- QUARTERLY: Quarterly business reviews and board reporting
- YEARLY: Annual performance and strategic planning
π Authentication Setup
JWT Token Management
import { AuthClient } from "@quub/auth-sdk";
const authClient = new AuthClient({
clientId: process.env.QUUB_CLIENT_ID,
clientSecret: process.env.QUUB_CLIENT_SECRET,
});
// Get access token
const token = await authClient.getAccessToken({
scopes: ["analytics:read", "analytics:write"],
});
// Use with Analytics client
const analyticsClient = new AnalyticsClient({
accessToken: token,
orgId: process.env.QUUB_ORG_ID,
});
Token Refresh Strategy
class TokenManager {
constructor(authClient) {
this.authClient = authClient;
this.token = null;
this.expiresAt = null;
}
async getToken() {
if (this.token && Date.now() < this.expiresAt - 60000) {
return this.token;
}
const response = await this.authClient.getAccessToken();
this.token = response.accessToken;
this.expiresAt = Date.now() + response.expiresIn * 1000;
return this.token;
}
}
β¨ Best Practices
1. Error Handling
try {
const report = await client.reports.create({...});
} catch (error) {
if (error.code === 'INVALID_DATE_RANGE') {
// Handle specific error
console.error('Invalid date range:', error.message);
} else if (error.code === 'RATE_LIMIT_EXCEEDED') {
// Implement backoff
await backoff(error.retryAfter);
// Retry request
} else {
// Log and alert
logger.error('Report generation failed', error);
alertOps(error);
}
}
2. Rate Limiting
import pLimit from "p-limit";
const limit = pLimit(5); // Max 5 concurrent requests
const reports = await Promise.all(
reportConfigs.map((config) => limit(() => client.reports.create(config)))
);
3. Caching Strategy
import NodeCache from "node-cache";
const cache = new NodeCache({ stdTTL: 300 }); // 5-minute TTL
async function getMetrics(params) {
const cacheKey = JSON.stringify(params);
const cached = cache.get(cacheKey);
if (cached) return cached;
const metrics = await client.metrics.getTrading(params);
cache.set(cacheKey, metrics);
return metrics;
}
π Security Guidelines
API Key Management
β Donβt:
// Never hardcode credentials
const client = new AnalyticsClient({
apiKey: "sk_live_abc123...",
orgId: "org_xyz789",
});
β Do:
// Use environment variables
const client = new AnalyticsClient({
apiKey: process.env.QUUB_API_KEY,
orgId: process.env.QUUB_ORG_ID,
});
Data Privacy
- Always set
includePII: falseunless absolutely necessary - Use data masking for sensitive fields
- Implement proper access controls
- Log all data access for audit trails
π Performance Optimization
1. Batch Operations
// Instead of multiple individual requests
for (const market of markets) {
await client.metrics.getTrading({ markets: [market] });
}
// Batch into single request
await client.metrics.getTrading({
markets: markets, // Multiple markets at once
});
2. Pagination
async function* fetchAllMetrics(params) {
let cursor = null;
do {
const response = await client.metrics.getTrading({
...params,
cursor,
});
yield response.data;
cursor = response.meta.nextCursor;
} while (cursor);
}
// Use with async iteration
for await (const batch of fetchAllMetrics(params)) {
processBatch(batch);
}
π§ Advanced Configuration
Custom Headers
const client = new AnalyticsClient({
apiKey: process.env.QUUB_API_KEY,
orgId: process.env.QUUB_ORG_ID,
headers: {
"X-Request-ID": generateRequestId(),
"X-App-Version": "1.0.0",
},
});
Webhook Integration
// Configure webhooks for report completion
await client.reports.create({
type: "COMPLIANCE_SUMMARY",
format: "PDF",
delivery: {
webhookUrl: "https://your-domain.com/webhooks/reports",
webhookSecret: process.env.WEBHOOK_SECRET,
},
});
// Verify webhook signatures
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac("sha256", secret);
const digest = hmac.update(payload).digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
π Troubleshooting
Common Issues
Issue: 401 Unauthorized
Cause: Invalid or expired JWT token
Solution:
// Implement token refresh
const token = await authClient.refreshToken();
analyticsClient.setAccessToken(token);
Issue: 403 Forbidden
Cause: Insufficient permissions or wrong orgId
Solution:
- Verify JWT contains correct scopes (
analytics:read,analytics:write) - Ensure
orgIdmatches the organization in JWT - Check role-based permissions
Issue: 429 Rate Limit Exceeded
Cause: Too many requests
Solution:
// Implement exponential backoff
async function withRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.code === "RATE_LIMIT_EXCEEDED" && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000;
await new Promise((r) => setTimeout(r, delay));
continue;
}
throw error;
}
}
}
π Monitoring & Observability
Logging
import winston from "winston";
const logger = winston.createLogger({
level: "info",
format: winston.format.json(),
transports: [new winston.transports.File({ filename: "analytics.log" })],
});
// Log all API calls
client.on("request", (req) => {
logger.info("API Request", {
method: req.method,
url: req.url,
requestId: req.headers["x-request-id"],
});
});
client.on("response", (res) => {
logger.info("API Response", {
status: res.status,
requestId: res.headers["x-request-id"],
duration: res.duration,
});
});
Metrics
import { Counter, Histogram } from "prom-client";
const requestCounter = new Counter({
name: "analytics_requests_total",
help: "Total number of Analytics API requests",
labelNames: ["method", "status"],
});
const requestDuration = new Histogram({
name: "analytics_request_duration_seconds",
help: "Analytics API request duration",
labelNames: ["method"],
});
π Additional Resources
- API Reference - Complete API documentation
- OpenAPI Specification - Machine-readable API spec
- Code Examples - Sample implementations
- Support - Get help from our team
Need help? Contact our support team or join our developer community.