Best Practices
A comprehensive guide to building production-ready applications with the Kixago API.
Overviewβ
This guide covers:
- π Performance Optimization - Speed up your application
- π Security Best Practices - Protect your API keys and data
- πΎ Caching Strategies - Reduce API calls and costs
- β‘ Rate Limiting - Stay within your plan limits
- ποΈ Code Organization - Structure your integration
- π§ͺ Testing Strategies - Build confidence in your code
- π Monitoring & Observability - Track usage and errors
- π’ Production Deployment - Launch checklist
Performance Optimizationβ
1. Implement Caching (Critical)β
The #1 performance optimization: Cache API responses for at least 30 seconds.
Why Cache?β
- β Faster responses: < 100ms (cached) vs 1-5s (fresh)
- β Lower costs: Reduce API usage by 90%+
- β Better UX: Instant page loads
- β Rate limit protection: Stay within your plan
Cache Strategyβ
The Kixago API caches responses for 30 seconds. You should do the same (or longer).
Simple in-memory cache:
// Simple TTL cache
class Cache<T> {
private store = new Map<string, { data: T; expires: number }>();
get(key: string): T | null {
const entry = this.store.get(key);
if (!entry) return null;
if (Date.now() > entry.expires) {
this.store.delete(key);
return null;
}
return entry.data;
}
set(key: string, data: T, ttlSeconds: number = 30): void {
this.store.set(key, {
data,
expires: Date.now() + ttlSeconds * 1000
});
}
}
// Usage
const cache = new Cache<RiskProfileResponse>();
async function getCachedProfile(address: string) {
const cached = cache.get(address);
if (cached) return cached;
const fresh = await getRiskProfile(address);
cache.set(address, fresh, 30);
return fresh;
}
Production-ready Redis cache:
// Redis cache
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
async function getCachedProfile(address: string) {
// Try cache
const cached = await redis.get(`kixago:profile:${address}`);
if (cached) {
return JSON.parse(cached);
}
// Fetch fresh
const fresh = await getRiskProfile(address);
// Cache for 30 seconds
await redis.setex(
`kixago:profile:${address}`,
30,
JSON.stringify(fresh)
);
return fresh;
}
2. Use Concurrent Requestsβ
When fetching multiple profiles, don't fetch sequentially - use concurrency.
β Bad (Sequential)β
// Takes 10-15 seconds for 5 wallets
const profiles = [];
for (const wallet of wallets) {
profiles.push(await getRiskProfile(wallet));
}
β Good (Concurrent)β
// Takes 2-3 seconds for 5 wallets
const profiles = await Promise.all(
wallets.map(wallet => getRiskProfile(wallet))
);
With rate limiting:
// Batch with rate limit (10 req/sec)
async function batchFetch(wallets: string[], concurrency = 10) {
const results = [];
for (let i = 0; i < wallets.length; i += concurrency) {
const batch = wallets.slice(i, i + concurrency);
const batchResults = await Promise.all(
batch.map(wallet => getRiskProfile(wallet))
);
results.push(...batchResults);
// Rate limit delay (if needed)
if (i + concurrency < wallets.length) {
await sleep(1000); // 1 second between batches
}
}
return results;
}
3. Optimize Data Transferβ
Only request and transfer data you actually need.
Cache Headersβ
Check the X-Cache-Status header to know if data is fresh:
const response = await fetch(url, { headers: { 'X-API-Key': apiKey } });
const cacheStatus = response.headers.get('X-Cache-Status');
if (cacheStatus === 'HIT') {
console.log('Served from cache (fast)');
} else {
console.log('Fresh data from blockchain');
}
Selective Parsingβ
If you only need the score, don't parse the entire response:
// β Bad - parse everything
const profile = await response.json();
const score = profile.defi_score.defi_score;
// β
Better - stream parse (for very large responses)
const text = await response.text();
const scoreMatch = text.match(/"defi_score":(\d+)/);
const score = scoreMatch ? parseInt(scoreMatch[1]) : null;
4. Implement Timeoutsβ
Always set appropriate timeouts to prevent hanging requests.
// 30-second timeout (matches API server timeout)
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
try {
const response = await fetch(url, {
headers: { 'X-API-Key': apiKey },
signal: controller.signal
});
return await response.json();
} finally {
clearTimeout(timeout);
}
Or using built-in timeout:
// Node.js 17.5+, modern browsers
const response = await fetch(url, {
headers: { 'X-API-Key': apiKey },
signal: AbortSignal.timeout(30000)
});
Security Best Practicesβ
1. Protect API Keys (Critical)β
Never expose API keys in:
- β Client-side JavaScript
- β Git repositories
- β Public URLs
- β Error messages
- β Logs
- β Screenshots
β Use Environment Variablesβ
# .env (add to .gitignore!)
KIXAGO_API_KEY=kixakey_your_key_here
// β
Correct
const apiKey = process.env.KIXAGO_API_KEY;
// β Wrong - hardcoded
const apiKey = 'kixakey_7eBHF9Ndxd...';
β Server-Side Proxy Patternβ
Never call Kixago API directly from browser:
// β WRONG - Browser can see API key
// frontend.js
const response = await fetch('https://api.kixago.com/v1/risk-profile/0x...', {
headers: { 'X-API-Key': EXPOSED_KEY } // β οΈ Visible in DevTools!
});
β Correct - Proxy through your backend:
// β
Frontend (no API key)
const response = await fetch('/api/wallet/0x...');
// β
Backend (API key safe)
app.get('/api/wallet/:address', async (req, res) => {
const profile = await kixagoClient.getRiskProfile(req.params.address);
res.json(profile);
});
2. Validate All Inputsβ
Always validate wallet addresses before sending to API:
function isValidAddress(address: string): boolean {
// Hex address: 0x + 40 hex chars
if (/^0x[a-fA-F0-9]{40}$/.test(address)) {
return true;
}
// ENS name: ends with .eth
if (/^[a-z0-9-]+\.eth$/i.test(address)) {
return true;
}
return false;
}
// Validate before API call
if (!isValidAddress(walletAddress)) {
throw new Error('Invalid wallet address format');
}
const profile = await getRiskProfile(walletAddress);
3. Implement Rate Limiting on Your Sideβ
Even with API rate limits, implement your own to protect your infrastructure:
// Simple rate limiter
class RateLimiter {
private requests: number[] = [];
constructor(
private maxRequests: number,
private windowMs: number
) {}
async acquire(): Promise<void> {
const now = Date.now();
// Remove old requests outside window
this.requests = this.requests.filter(t => t > now - this.windowMs);
if (this.requests.length >= this.maxRequests) {
const oldestRequest = Math.min(...this.requests);
const waitTime = this.windowMs - (now - oldestRequest);
await new Promise(resolve => setTimeout(resolve, waitTime));
return this.acquire(); // Retry
}
this.requests.push(now);
}
}
// Usage: 10 requests per second
const limiter = new RateLimiter(10, 1000);
async function fetchWithRateLimit(address: string) {
await limiter.acquire();
return getRiskProfile(address);
}
4. Sanitize Error Messagesβ
Don't leak sensitive data in error messages:
// β Bad - exposes API key
catch (err) {
console.error(`Failed with key ${apiKey}: ${err}`);
}
// β
Good - sanitized
catch (err) {
console.error('API request failed:', {
error: err.message,
statusCode: err.statusCode,
// No API key!
});
}
5. Use Different Keys per Environmentβ
Create separate API keys for:
- Development - Local testing
- Staging - QA environment
- Production - Live application
Benefits:
- Revoke dev keys without affecting production
- Track usage separately
- Different rate limits per environment
- Easier debugging
# .env.development
KIXAGO_API_KEY=kixakey_dev_...
# .env.production
KIXAGO_API_KEY=kixakey_prod_...
Caching Strategiesβ
Cache Layersβ
Implement multiple cache layers for optimal performance:
βββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 1: In-Memory Cache (< 1ms) β
β ββ LRU Cache β
β ββ TTL: 30 seconds β
ββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β (cache miss)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 2: Redis Cache (1-5ms) β
β ββ Shared across servers β
β ββ TTL: 30 seconds β
ββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β (cache miss)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 3: Kixago API (1-5s) β
β ββ Fresh on-chain data β
βββββββββββββββββββββββββββββββββββββββββββββββ
Implementation:
class MultiLayerCache {
private memCache = new Map();
constructor(private redis: Redis) {}
async get(key: string): Promise<any> {
// Layer 1: Memory
if (this.memCache.has(key)) {
const { data, expires } = this.memCache.get(key);
if (Date.now() < expires) {
console.log('β
Memory cache HIT');
return data;
}
this.memCache.delete(key);
}
// Layer 2: Redis
const cached = await this.redis.get(key);
if (cached) {
console.log('β
Redis cache HIT');
const data = JSON.parse(cached);
// Populate memory cache
this.memCache.set(key, {
data,
expires: Date.now() + 30000
});
return data;
}
return null;
}
async set(key: string, data: any): Promise<void> {
// Set in both layers
this.memCache.set(key, {
data,
expires: Date.now() + 30000
});
await this.redis.setex(key, 30, JSON.stringify(data));
}
}
Cache Warmingβ
Pre-populate cache for known wallets:
// Warm cache on server startup
async function warmCache(wallets: string[]) {
console.log(`Warming cache for ${wallets.length} wallets...`);
for (const wallet of wallets) {
try {
await getCachedProfile(wallet); // Will cache the result
} catch (err) {
console.warn(`Failed to warm cache for ${wallet}`);
}
}
console.log('β
Cache warming complete');
}
// Run on startup
warmCache([
'0xf0bb20865277aBd641a307eCe5Ee04E79073416C',
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
// ... frequently accessed wallets
]);
Cache Invalidationβ
Invalidate cache when you know data has changed:
async function invalidateCache(walletAddress: string) {
const cacheKey = `kixago:profile:${walletAddress}`;
// Clear from Redis
await redis.del(cacheKey);
// Clear from memory
memCache.delete(cacheKey);
console.log(`β
Cache invalidated for ${walletAddress}`);
}
// Example: User repays debt
async function handleDebtRepayment(walletAddress: string) {
// Process repayment...
// Invalidate cache to get fresh data
await invalidateCache(walletAddress);
}
Rate Limiting Managementβ
Monitor Your Usageβ
Track API usage to avoid hitting limits:
// Track requests in sliding window
class UsageTracker {
private requests: { timestamp: number; endpoint: string }[] = [];
track(endpoint: string) {
this.requests.push({
timestamp: Date.now(),
endpoint
});
// Keep last 1 hour
const oneHourAgo = Date.now() - 3600000;
this.requests = this.requests.filter(r => r.timestamp > oneHourAgo);
}
getUsage() {
const now = Date.now();
return {
lastHour: this.requests.length,
lastMinute: this.requests.filter(r => r.timestamp > now - 60000).length,
lastSecond: this.requests.filter(r => r.timestamp > now - 1000).length,
};
}
isNearLimit(plan: 'developer' | 'startup' | 'institution') {
const limits = {
developer: { perSecond: 10, perMonth: 10000 },
startup: { perSecond: 50, perMonth: 100000 },
institution: { perSecond: 200, perMonth: 1000000 }
};
const limit = limits[plan];
const usage = this.getUsage();
return usage.lastSecond > limit.perSecond * 0.8; // 80% threshold
}
}
const tracker = new UsageTracker();
async function monitoredFetch(address: string) {
tracker.track('risk-profile');
if (tracker.isNearLimit('developer')) {
console.warn('β οΈ Approaching rate limit!');
}
return getRiskProfile(address);
}
Graceful Degradationβ
Handle rate limits gracefully:
async function fetchWithFallback(address: string) {
try {
return await getRiskProfile(address);
} catch (err) {
if (err.statusCode === 429) {
// Rate limited - use stale cache if available
const staleCache = await getStaleCache(address);
if (staleCache) {
console.warn('β οΈ Rate limited - using stale cache');
return {
...staleCache,
_stale: true,
_message: 'Data may be outdated due to rate limiting'
};
}
}
throw err;
}
}
async function getStaleCache(address: string) {
// Try to get cache even if expired
const key = `kixago:profile:${address}`;
const cached = await redis.get(key);
return cached ? JSON.parse(cached) : null;
}
Request Queuingβ
Queue requests to smooth out bursts:
class RequestQueue {
private queue: Array<() => Promise<any>> = [];
private processing = false;
private requestsPerSecond: number;
constructor(requestsPerSecond: number) {
this.requestsPerSecond = requestsPerSecond;
}
async add<T>(fn: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
const result = await fn();
resolve(result);
} catch (err) {
reject(err);
}
});
if (!this.processing) {
this.process();
}
});
}
private async process() {
this.processing = true;
while (this.queue.length > 0) {
const fn = this.queue.shift()!;
await fn();
// Delay to respect rate limit
await new Promise(resolve =>
setTimeout(resolve, 1000 / this.requestsPerSecond)
);
}
this.processing = false;
}
}
// Usage
const queue = new RequestQueue(10); // 10 req/sec
async function queuedFetch(address: string) {
return queue.add(() => getRiskProfile(address));
}
Code Organizationβ
Centralized Clientβ
Create a single client instance:
// lib/kixago.ts
export class KixagoClient {
private static instance: KixagoClient;
private constructor(
private apiKey: string,
private cache: Cache
) {}
static getInstance(): KixagoClient {
if (!KixagoClient.instance) {
KixagoClient.instance = new KixagoClient(
process.env.KIXAGO_API_KEY!,
new RedisCache()
);
}
return KixagoClient.instance;
}
async getRiskProfile(address: string) {
// Implementation...
}
}
// Usage everywhere
import { KixagoClient } from '@/lib/kixago';
const client = KixagoClient.getInstance();
const profile = await client.getRiskProfile(address);
Separation of Concernsβ
Organize by feature:
src/
βββ services/
β βββ kixago/
β β βββ client.ts # API client
β β βββ cache.ts # Caching logic
β β βββ types.ts # TypeScript types
β β βββ utils.ts # Helper functions
β β
β βββ underwriting/
β β βββ service.ts # Underwriting logic
β β βββ rules.ts # Business rules
β β
β βββ monitoring/
β βββ alerts.ts # Alerting logic
β βββ tracker.ts # Usage tracking
β
βββ controllers/
β βββ wallet.controller.ts # API endpoints
β
βββ config/
βββ kixago.config.ts # Configuration
Configuration Managementβ
Centralize configuration:
// config/kixago.config.ts
export const kixagoConfig = {
apiKey: process.env.KIXAGO_API_KEY!,
baseUrl: process.env.KIXAGO_BASE_URL || 'https://api.kixago.com',
cache: {
ttl: parseInt(process.env.KIXAGO_CACHE_TTL || '30'),
redis: {
url: process.env.REDIS_URL
}
},
rateLimit: {
requestsPerSecond: parseInt(process.env.KIXAGO_RATE_LIMIT || '10')
},
retry: {
maxRetries: 3,
initialDelay: 1000,
maxDelay: 30000
},
timeout: 30000,
monitoring: {
enabled: process.env.NODE_ENV === 'production',
sentry: process.env.SENTRY_DSN
}
};
// Validate configuration on startup
export function validateConfig() {
if (!kixagoConfig.apiKey) {
throw new Error('KIXAGO_API_KEY is required');
}
if (!kixagoConfig.apiKey.startsWith('kixakey_')) {
throw new Error('Invalid KIXAGO_API_KEY format');
}
}
Testing Strategiesβ
Mock API Responsesβ
Create reusable mocks for testing:
// tests/mocks/kixago.mock.ts
export const mockRiskProfile = {
wallet_address: '0xTest...',
total_collateral_usd: 100000,
total_borrowed_usd: 30000,
global_health_factor: 3.2,
global_ltv: 30.0,
positions_at_risk_count: 0,
defi_score: {
defi_score: 750,
risk_level: 'Very Low Risk',
risk_category: 'VERY_LOW_RISK',
// ... rest of fields
}
};
export function mockKixagoClient() {
return {
getRiskProfile: jest.fn().mockResolvedValue(mockRiskProfile)
};
}
// Usage in tests
import { mockKixagoClient } from './mocks/kixago.mock';
test('underwriting approves high score', async () => {
const client = mockKixagoClient();
const service = new UnderwritingService(client);
const decision = await service.underwrite('0xTest...', 10000);
expect(decision.decision).toBe('APPROVED');
});
Integration Testsβ
Test actual API integration (use sparingly):
// tests/integration/kixago.test.ts
describe('Kixago API Integration', () => {
// Only run if API key is present
const apiKey = process.env.KIXAGO_TEST_API_KEY;
const shouldRun = apiKey ? test : test.skip;
shouldRun('fetches real profile', async () => {
const client = new KixagoClient(apiKey);
const profile = await client.getRiskProfile(
'0xf0bb20865277aBd641a307eCe5Ee04E79073416C'
);
expect(profile.wallet_address).toBe('0xf0bb20865277aBd641a307eCe5Ee04E79073416C');
expect(profile.defi_score).toBeDefined();
}, 30000); // 30s timeout
});
Contract Testingβ
Ensure your code handles API contract changes:
// tests/contract/kixago.contract.test.ts
import Ajv from 'ajv';
import { riskProfileSchema } from './schemas/risk-profile.schema.json';
const ajv = new Ajv();
test('API response matches expected schema', async () => {
const profile = await getRiskProfile('0xTest...');
const validate = ajv.compile(riskProfileSchema);
const valid = validate(profile);
if (!valid) {
console.error('Schema validation errors:', validate.errors);
}
expect(valid).toBe(true);
});
Monitoring & Observabilityβ
Metrics to Trackβ
// Track key metrics
class KixagoMetrics {
track(metric: string, value: number, tags: Record<string, string> = {}) {
// Send to monitoring service (Datadog, Prometheus, etc.)
metrics.gauge(`kixago.${metric}`, value, tags);
}
increment(metric: string, tags: Record<string, string> = {}) {
metrics.increment(`kixago.${metric}`, tags);
}
timing(metric: string, duration: number, tags: Record<string, string> = {}) {
metrics.timing(`kixago.${metric}`, duration, tags);
}
}
const kixagoMetrics = new KixagoMetrics();
// Track API calls
async function monitoredGetRiskProfile(address: string) {
const startTime = Date.now();
try {
const profile = await getRiskProfile(address);
kixagoMetrics.timing('response_time', Date.now() - startTime, {
cached: profile._cached ? 'true' : 'false'
});
kixagoMetrics.increment('success', {
has_score: profile.defi_score ? 'true' : 'false'
});
if (profile.aggregation_errors) {
kixagoMetrics.increment('partial_failure', {
protocols: Object.keys(profile.aggregation_errors).join(',')
});
}
return profile;
} catch (err) {
kixagoMetrics.increment('error', {
type: err.name,
statusCode: err.statusCode?.toString() || 'unknown'
});
throw err;
}
}
Logging Best Practicesβ
// Structured logging
import logger from './logger';
async function getRiskProfileWithLogging(address: string) {
const requestId = generateRequestId();
logger.info('Fetching risk profile', {
requestId,
address,
timestamp: new Date().toISOString()
});
try {
const profile = await getRiskProfile(address);
logger.info('Risk profile fetched successfully', {
requestId,
address,
score: profile.defi_score?.defi_score,
cached: profile._cached,
duration: '1.2s'
});
return profile;
} catch (err) {
logger.error('Failed to fetch risk profile', {
requestId,
address,
error: err.message,
statusCode: err.statusCode,
stack: err.stack
});
throw err;
}
}
Health Checksβ
Implement health checks for monitoring:
// Health check endpoint
app.get('/health/kixago', async (req, res) => {
try {
// Test API connectivity with a known wallet
const testAddress = '0xf0bb20865277aBd641a307eCe5Ee04E79073416C';
const startTime = Date.now();
const profile = await getRiskProfile(testAddress);
const duration = Date.now() - startTime;
res.json({
status: 'healthy',
api: 'kixago',
response_time_ms: duration,
timestamp: new Date().toISOString()
});
} catch (err) {
res.status(503).json({
status: 'unhealthy',
api: 'kixago',
error: err.message,
timestamp: new Date().toISOString()
});
}
});
Production Deployment Checklistβ
Pre-Launch Checklistβ
-
API Key Management
- Production API key created
- Stored in secure secret manager (not .env file)
- Different keys for staging/production
- Key rotation plan in place
-
Caching
- Redis configured and tested
- Cache TTL set to 30+ seconds
- Cache warming for known wallets
- Cache invalidation strategy
-
Error Handling
- Retry logic implemented
- Exponential backoff configured
- Partial failure handling tested
- Error logging to monitoring service
-
Rate Limiting
- Usage tracking implemented
- Rate limit monitoring
- Graceful degradation plan
- Upgrade plan if needed
-
Monitoring
- Metrics tracking configured
- Alerts set up (error rate, latency, etc.)
- Dashboards created
- On-call rotation defined
-
Testing
- Unit tests passing
- Integration tests passing
- Load testing completed
- Edge cases tested
-
Documentation
- Internal docs written
- Runbook created
- Team trained
Environment Variables Templateβ
# .env.production
NODE_ENV=production
# Kixago API
KIXAGO_API_KEY=kixakey_prod_...
KIXAGO_BASE_URL=https://api.kixago.com
KIXAGO_CACHE_TTL=30
KIXAGO_RATE_LIMIT=10
# Redis Cache
REDIS_URL=redis://prod-redis:6379
REDIS_PASSWORD=...
# Monitoring
SENTRY_DSN=https://...
DATADOG_API_KEY=...
# Application
PORT=3000
LOG_LEVEL=info
Scaling Considerationsβ
Horizontal Scaling:
// Use Redis for shared cache across instances
// Multiple app servers can share the same cache
βββββββββββ βββββββββββ βββββββββββ
β App #1 ββββββΆβ Redis βββββββ App #2 β
βββββββββββ βββββββββββ βββββββββββ
β β
ββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββ
β Kixago API β
βββββββββββββββββ
Load Balancing:
# nginx.conf
upstream app_servers {
least_conn; # Route to least busy server
server app1:3000;
server app2:3000;
server app3:3000;
}
server {
listen 80;
location / {
proxy_pass http://app_servers;
proxy_set_header X-Request-ID $request_id;
}
}
Performance Benchmarksβ
Target Metricsβ
| Metric | Target | Notes |
|---|---|---|
| Cache Hit Rate | > 80% | Most requests should be cached |
| P50 Response Time | < 100ms | Median response (cached) |
| P95 Response Time | < 2s | 95th percentile (fresh) |
| P99 Response Time | < 5s | 99th percentile |
| Error Rate | < 1% | Including partial failures |
| Uptime | > 99.9% | Your service uptime |
Common Pitfalls to Avoidβ
β Don't Do Thisβ
// β No caching
async function getScore(address: string) {
return (await getRiskProfile(address)).defi_score.defi_score;
}
// β Hardcoded API key
const client = new KixagoClient('kixakey_abc123');
// β No error handling
const profile = await fetch(url).then(r => r.json());
// β No timeout
const profile = await fetch(url);
// β Exposing API key in frontend
const profile = await fetch(apiUrl, {
headers: { 'X-API-Key': window.KIXAGO_KEY }
});
// β Sequential requests
for (const wallet of wallets) {
await getRiskProfile(wallet);
}
// β Ignoring aggregation errors
const profile = await getRiskProfile(address);
// No check for partial failures
// β No validation
const profile = await getRiskProfile(userInput); // Potential injection
β Do This Insteadβ
// β
With caching
const cachedClient = new CachedKixagoClient(apiKey);
const profile = await cachedClient.getRiskProfile(address);
// β
Environment variables
const client = new KixagoClient(process.env.KIXAGO_API_KEY);
// β
Error handling
try {
const profile = await getRiskProfile(address);
} catch (err) {
handleError(err);
}
// β
With timeout
const profile = await fetch(url, {
signal: AbortSignal.timeout(30000)
});
// β
Server-side proxy
// Backend only - API key never exposed
// β
Concurrent requests
const profiles = await Promise.all(
wallets.map(w => getRiskProfile(w))
);
// β
Check aggregation errors
if (profile.aggregation_errors) {
logger.warn('Partial failure', profile.aggregation_errors);
}
// β
Validate inputs
if (!isValidAddress(address)) throw new Error('Invalid address');
const profile = await getRiskProfile(address);
Quick Referenceβ
Essential Code Snippetsβ
Complete production-ready client:
import { createClient } from './lib/kixago-client';
const client = createClient({
apiKey: process.env.KIXAGO_API_KEY!,
cache: {
enabled: true,
ttl: 30,
redis: process.env.REDIS_URL
},
retry: {
maxRetries: 3,
backoff: 'exponential'
},
timeout: 30000,
monitoring: {
enabled: true,
metrics: true,
logging: true
}
});
// Use everywhere
const profile = await client.getRiskProfile(address);
Next Stepsβ
Need Help?β
- Architecture questions? Email api@kixago.com
- Performance issues? Share your metrics with support
- Custom requirements? Contact enterprise sales
---