Analytics API Overview
The TokenOps Analytics API provides comprehensive insights, real-time monitoring, and data analytics for all TokenOps contracts. It offers RESTful endpoints, WebSocket connections, webhook notifications, and advanced querying capabilities for vesting, staking, airdrops, and token distribution contracts.
What is the Analytics API?
The Analytics API is a RESTful service that provides insights and data for TokenOps vesting contracts and token analytics, offering:
- Vesting Analytics: Comprehensive vesting contract data and insights
- Token Supply Data: Total supply and vested supply tracking
- Event Monitoring: Webhook subscriptions for vesting events
- Grant Management: Detailed vesting grant information and filtering
- Contract Insights: Advanced analytics for vesting performance
Key Features
- Multi-Chain Support: Ethereum mainnet, testnets, and compatible chains
- Webhook Notifications: Real-time event notifications for vesting contracts
- Advanced Filtering: Query grants by recipient, token, event type, and more
- Pagination Support: Efficient data retrieval for large datasets
- Rate Limiting: Fair usage policies with API key authentication
- RESTful Design: Standard HTTP methods with JSON responses
API Architecture
API Client Setup
Installation and Configuration
import { TokenOpsApi } from 'tokenops-sdk';
// Initialize API client
const api = new TokenOpsApi('your-api-key-here');
// Test connection
const pingResponse = await api.ping();
console.log('API Status:', pingResponse.message);
Authentication
The API uses bearer token authentication. Your API key is included in the Authorization header for all requests:
// API key is automatically included in all requests
const api = new TokenOpsApi(process.env.TOKENOPS_API_KEY!);
// Test authentication with ping
try {
const response = await api.ping();
console.log('Authentication successful:', response);
} catch (error) {
console.error('Authentication failed:', error);
}
Core API Endpoints
1. Vesting Analytics
Comprehensive vesting contract insights and data:
// Get vesting contract overview
const vestingInfo = await api.vesting(chainId, contractAddress, tokenAddress);
console.log('Vesting info:', {
address: vestingInfo.data.address,
chainId: vestingInfo.data.chainId,
token: vestingInfo.data.token,
totalAllocated: vestingInfo.data.totalAllocated,
totalWithdrawn: vestingInfo.data.totalWithdrawn,
totalClaimable: vestingInfo.data.totalClaimable,
totalVested: vestingInfo.data.totalVested,
grantsCount: vestingInfo.data.grantsCount,
latestBlockUpdate: vestingInfo.data.latestBlockUpdate
});
// Get specific vesting grants with filtering
const grants = await api.vestingGrants(
chainId,
contractAddress,
tokenAddress, // Optional: filter by token
recipientAddress, // Optional: filter by recipient
eventType, // Optional: filter by event type
page, // Optional: page number (default: 1)
size // Optional: page size (default: 10)
);
console.log('Grants:', {
total: grants.total,
page: grants.page,
size: grants.size,
pages: grants.pages,
items: grants.items
});
// Get vesting insights and analytics
const insights = await api.vestingInsights(
chainId,
contractAddress,
tokenAddress, // Optional: filter by token
recipientAddress, // Optional: filter by recipient
page, // Optional: page number
size // Optional: page size
);
console.log('Insights:', insights.items);
// Get vesting events
const events = await api.vestingEvents(
chainId,
contractAddress,
tokenAddress, // Optional: filter by token
recipientAddress, // Optional: filter by recipient
eventType, // Optional: filter by event type
page, // Optional: page number
size // Optional: page size
);
console.log('Events:', events.items);
2. Token Supply Analytics
Track token supply and distribution:
// Get total supply for a token
const totalSupply = await api.totalSupply(tokenAddress);
console.log('Total supply:', totalSupply.total_supply);
// Get vested supply for a token
const vestedSupply = await api.vestedSupply(tokenAddress);
console.log('Vested supply:', vestedSupply.vested_supply);
// Calculate supply analytics
const supplyAnalytics = {
totalSupply: totalSupply.total_supply,
vestedSupply: vestedSupply.vested_supply,
vestedPercentage: Number(vestedSupply.vested_supply) / Number(totalSupply.total_supply) * 100,
circulatingSupply: totalSupply.total_supply - vestedSupply.vested_supply
};
console.log('Supply analytics:', supplyAnalytics);
3. Contract Analytics
Get vesting contract count for multiple wallets:
// Get contract count for multiple wallets
const walletAddresses = [
'0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36',
'0x123...',
'0x456...'
];
const contractCounts = await api.vestingContractCount(walletAddresses);
console.log('Contract counts:', contractCounts.results);
// Process results
contractCounts.results.forEach(result => {
console.log(`Wallet ${result.recipient}: ${result.countract_count} contracts`);
});
Real-time Event Monitoring
Webhook Subscriptions
The API provides webhook subscriptions for real-time vesting event notifications:
// Subscribe to vesting events via webhook
async function subscribeToVestingEvents() {
const subscription = await api.vestingSubscribe(
chainId,
contractAddress,
['VestingCreated', 'TokensClaimed', 'VestingRevoked'], // Desired events
'https://your-app.com/webhooks/vesting' // Your webhook URL
);
console.log('Webhook subscription response:', subscription);
// Response: { status_code: 200, response_type: 'success', description: 'Subscription created' }
}
// Example with error handling
async function setupVestingWebhook() {
try {
const result = await api.vestingSubscribe(
11155111, // Sepolia testnet
'0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36',
['VestingCreated', 'TokensClaimed'],
'https://your-domain.com/api/webhooks/vesting'
);
if (result.status_code === 200) {
console.log('✅ Webhook subscription successful');
}
} catch (error) {
console.error('❌ Webhook subscription failed:', error);
}
}
Webhook Handler Implementation
Create a webhook endpoint to receive real-time event notifications:
// Express.js webhook handler
import express from 'express';
import crypto from 'crypto';
const app = express();
// Webhook endpoint for vesting events
app.post('/webhooks/vesting', express.json(), (req, res) => {
const event = req.body;
console.log('Received vesting event:', event);
// Handle different event types
switch (event.eventType) {
case 'VestingCreated':
handleVestingCreated(event);
break;
case 'TokensClaimed':
handleTokensClaimed(event);
break;
case 'VestingRevoked':
handleVestingRevoked(event);
break;
default:
console.log('Unknown event type:', event.eventType);
}
res.status(200).send('OK');
});
function handleVestingCreated(event: any) {
console.log('New vesting created:', {
contractAddress: event.contractAddress,
recipient: event.recipient,
amount: event.amount,
vestingId: event.vestingId
});
// Send notification to user
sendNotification(event.recipient, 'vesting_created', {
amount: formatTokens(event.amount),
vestingId: event.vestingId
});
}
function handleTokensClaimed(event: any) {
console.log('Tokens claimed:', {
recipient: event.recipient,
amount: event.amount,
vestingId: event.vestingId,
transactionHash: event.transactionHash
});
// Update user dashboard
updateUserDashboard(event.recipient, {
newClaimAmount: event.amount,
transactionHash: event.transactionHash
});
// Send email notification
sendEmailNotification(event.recipient, 'tokens_claimed', {
amount: formatTokens(event.amount),
transactionHash: event.transactionHash
});
}
function handleVestingRevoked(event: any) {
console.log('Vesting revoked:', {
recipient: event.recipient,
vestingId: event.vestingId,
revokedAmount: event.revokedAmount
});
// Notify user about revocation
sendNotification(event.recipient, 'vesting_revoked', {
vestingId: event.vestingId,
revokedAmount: formatTokens(event.revokedAmount)
});
}
// Helper functions
function formatTokens(amount: string): string {
return (BigInt(amount) / BigInt(10**18)).toString();
}
function sendNotification(recipient: string, type: string, data: any) {
// Implementation depends on your notification system
console.log(`Sending ${type} notification to ${recipient}:`, data);
}
function updateUserDashboard(recipient: string, data: any) {
// Update your application's user dashboard
console.log(`Updating dashboard for ${recipient}:`, data);
}
function sendEmailNotification(recipient: string, type: string, data: any) {
// Send email notification
console.log(`Sending email to ${recipient}:`, { type, data });
}
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
Testing Webhooks
// Test webhook subscription
async function testWebhookSubscription() {
const chainId = 11155111; // Sepolia testnet
const contractAddress = '0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36';
const events = ['VestingCreated', 'TokensClaimed', 'VestingRevoked'];
const webhookUrl = 'https://webhook.site/your-unique-url'; // Use webhook.site for testing
try {
const subscription = await api.vestingSubscribe(
chainId,
contractAddress,
events,
webhookUrl
);
console.log('Test subscription created:', subscription);
// Now perform actions on the contract to trigger events
// You should see the events appear on webhook.site
} catch (error) {
console.error('Test subscription failed:', error);
}
}
Error Handling
Basic Error Handling
// Handle API errors properly
async function safeApiCall() {
try {
const vestingData = await api.vesting(1, contractAddress);
console.log('Success:', vestingData);
} catch (error) {
if (error.response) {
// API returned an error response
console.error('API Error:', {
status: error.response.status,
message: error.response.data?.message || error.message
});
} else if (error.request) {
// Network error
console.error('Network Error:', error.message);
} else {
// Other error
console.error('Error:', error.message);
}
}
}
Retry Logic
// Implement retry logic for failed requests
class RetryableApi {
private api: TokenOpsApi;
constructor(apiKey: string) {
this.api = new TokenOpsApi(apiKey);
}
async withRetry<T>(operation: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw error;
}
// Wait before retry (exponential backoff)
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
}
}
// Usage
const retryableApi = new RetryableApi(apiKey);
const vestingData = await retryableApi.withRetry(
() => api.vesting(chainId, contractAddress)
);
Pagination Example
// Handle paginated responses
async function getAllVestingGrants(chainId: number, contractAddress: string) {
const allGrants = [];
let page = 1;
const pageSize = 100;
while (true) {
const response = await api.vestingGrants(
chainId,
contractAddress,
undefined, // tokenAddress
undefined, // recipientAddress
undefined, // eventType
page,
pageSize
);
allGrants.push(...response.items);
console.log(`Page ${page}: ${response.items.length} grants`);
// Check if we've reached the last page
if (response.items.length < pageSize || page >= response.pages) {
break;
}
page++;
}
console.log(`Total grants retrieved: ${allGrants.length}`);
return allGrants;
}
Complete Usage Example
Here's a comprehensive example using all available API methods:
import { TokenOpsApi } from 'tokenops-sdk';
async function demonstrateTokenOpsApi() {
const api = new TokenOpsApi(process.env.TOKENOPS_API_KEY!);
// Test connection
const pingResponse = await api.ping();
console.log('✅ Connected:', pingResponse.message);
// Contract and token addresses
const chainId = 11155111; // Sepolia
const contractAddress = '0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36';
const tokenAddress = '0x123...'; // Your token address
try {
// 1. Get vesting contract overview
const vestingInfo = await api.vesting(chainId, contractAddress, tokenAddress);
console.log('📊 Vesting Info:', {
totalAllocated: vestingInfo.data.totalAllocated,
totalWithdrawn: vestingInfo.data.totalWithdrawn,
grantsCount: vestingInfo.data.grantsCount
});
// 2. Get vesting grants with pagination
const grants = await api.vestingGrants(chainId, contractAddress, tokenAddress, undefined, undefined, 1, 10);
console.log('📋 Grants:', grants.items.length, 'of', grants.total);
// 3. Get vesting insights
const insights = await api.vestingInsights(chainId, contractAddress, tokenAddress);
console.log('💡 Insights:', insights.items.length, 'insights available');
// 4. Get vesting events
const events = await api.vestingEvents(chainId, contractAddress, tokenAddress, undefined, 'TokensClaimed');
console.log('📅 Events:', events.items.length, 'claim events');
// 5. Get token supply data
const totalSupply = await api.totalSupply(tokenAddress);
const vestedSupply = await api.vestedSupply(tokenAddress);
console.log('📈 Supply Data:', {
total: totalSupply.total_supply,
vested: vestedSupply.vested_supply,
vestedPercentage: (Number(vestedSupply.vested_supply) / Number(totalSupply.total_supply)) * 100
});
// 6. Get contract counts for wallets
const wallets = ['0x742d35Cc6632C0532c718F4D8c2b1D1f8a1B9F36', '0x123...'];
const contractCounts = await api.vestingContractCount(wallets);
console.log('🏠 Contract Counts:', contractCounts.results);
// 7. Subscribe to webhook notifications
const webhook = await api.vestingSubscribe(
chainId,
contractAddress,
['VestingCreated', 'TokensClaimed', 'VestingRevoked'],
'https://your-app.com/webhook/vesting'
);
console.log('🔔 Webhook subscribed:', webhook.status_code === 200);
} catch (error) {
console.error('❌ API Error:', error.message);
}
}
// Run the demo
demonstrateTokenOpsApi();
Next Steps
Now that you understand the Analytics API:
- Get API Key - Sign up for API access at the TokenOps dashboard
- Test Integration - Try the code examples provided in this documentation
- Set up Webhooks - Configure real-time notifications using the webhook methods
- Explore SDK - Use the full TokenOps SDK
Resources
- API Base URL:
https://api.tokenops.xyz/
- Authentication: Bearer token (API key required)
- Rate Limits: Contact support for current limits
- SDK Documentation: Quick Start