Overview
The Royalti.io platform provides comprehensive royalty processing and distribution capabilities. This guide covers uploading royalty data, processing splits, and managing accounting workflows.
Authentication
All royalty endpoints require authentication with a Bearer token.
 
Royalty Processing Workflow
Upload Royalty Data
Upload CSV, Excel, or ZIP files containing royalty statements from DSPs or distributors.const formData = new FormData();
formData.append('file', fileBuffer, 'royalties-202401.csv');
formData.append('source', 'spotify');
formData.append('period', '2024-01');
const response = await fetch('https://api.royalti.io/royalties/upload', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  },
  body: formData
});
 Pattern Recognition
The system automatically detects file format and matches against known templates.Pattern recognition analyzes headers, column structure, and data patterns to identify the source automatically.
 Process Splits
Calculate royalty distributions based on configured splits.const response = await fetch('https://api.royalti.io/accounting/calculate', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    productId: 'prod-123',
    period: '2024-01'
  })
});
 Review and Approve
Review calculated splits and approve for payment processing.const response = await fetch(`https://api.royalti.io/accounting/${accountingId}/approve`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  }
});
  
Split Configuration
Creating Splits
Define revenue split configurations for products and assets:
const response = await fetch('https://api.royalti.io/splits/', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    productId: 'prod-123',
    type: 'master',
    splits: [
      {
        userId: 'user-1',
        sharePercentage: 50,
        role: 'artist'
      },
      {
        userId: 'user-2',
        sharePercentage: 30,
        role: 'producer'
      },
      {
        userId: 'user-3',
        sharePercentage: 20,
        role: 'writer'
      }
    ]
  })
});
 
Temporal Splits
Handle split changes over time:
const response = await fetch('https://api.royalti.io/splits/succession', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    previousSplitId: 'split-1',
    effectiveDate: '2024-06-01',
    newSplits: [
      { userId: 'user-1', sharePercentage: 60 },
      { userId: 'user-2', sharePercentage: 40 }
    ]
  })
});
 
Analytics and Reporting
Query Revenue Data
Use BigQuery integration for advanced analytics:
const response = await fetch('https://api.royalti.io/royalties/analytics/artist', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    artistId: 'artist-123',
    startDate: '2024-01-01',
    endDate: '2024-12-31'
  })
});
 
Available Analytics Queries
- Artist Query: Revenue by artist across all sources
 
- Catalog Query: Product/asset performance
 
- Country Query: Geographic distribution
 
- DSP Query: Platform-specific analytics
 
- Monthly Query: Time-series trends
 
- Sale Type Query: Stream vs download breakdown
 
Best Practices
Data Validation
Always validate uploaded files match expected schemas before processing large batches.
 
Split Accuracy
Ensure splits total 100%:
function validateSplits(splits) {
  const total = splits.reduce((sum, split) => sum + split.sharePercentage, 0);
  if (Math.abs(total - 100) > 0.01) {
    throw new Error(`Splits must total 100%, got ${total}%`);
  }
}
 
Caching Strategies
Implement caching for frequently accessed accounting data:
const cache = new Map();
async function getAccountingData(productId, period) {
  const cacheKey = `${productId}:${period}`;
  if (cache.has(cacheKey)) {
    return cache.get(cacheKey);
  }
  const data = await fetchAccountingData(productId, period);
  cache.set(cacheKey, data);
  return data;
}