Skip to main content

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

1

Upload Royalty Data

Upload CSV, Excel, or ZIP files containing royalty statements from DSPs or distributors.
Node.js
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
});
2

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.
3

Process Splits

Calculate royalty distributions based on configured splits.
Node.js
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'
  })
});
4

Review and Approve

Review calculated splits and approve for payment processing.
Node.js
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:
Node.js
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:
Node.js
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:
Node.js
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%:
Node.js
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:
Node.js
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;
}