Skip to main content

Overview

FUGA is a leading music distribution platform that delivers catalog to 400+ Digital Service Providers (DSPs) worldwide. The Royalti.io API integrates with FUGA using CSV metadata files and FTP file uploads, enabling automated delivery of releases to streaming platforms.

Key Features

  • Automated CSV Generation - API automatically formats your catalog into FUGA’s CSV template
  • FTP Upload Management - Handles file uploads including audio files and artwork
  • Webhook Tracking - Real-time delivery status updates from FUGA
  • Batch Delivery - Deliver multiple products simultaneously
  • Validation - Pre-delivery validation to catch errors early
  • Monitoring - Built-in health checks and delivery analytics

Authentication

FUGA delivery endpoints require authentication and the “DDEX & Deliveries” addon to be enabled.

FUGA Workflow

1

Configure FUGA Provider

Set up your FUGA FTP credentials and webhook salt for delivery tracking.
  • Node.js
  • Python
  • cURL
const response = await fetch('https://api.royalti.io/ddex/tenant-providers', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    providerId: 'fuga-csv-ftp',
    credentials: {
      host: 'ftp.fuga.com',
      username: 'your-username',
      password: 'your-password',
      port: 21,
      webhookSalt: 'your-webhook-salt'
    },
    isActive: true
  })
});

const result = await response.json();
console.log('Provider configured:', result.data.id);
All FTP credentials and webhook salts are automatically encrypted at rest. No plaintext credentials are stored in the database.
2

Prepare Product Metadata

Ensure your product has all required fields for FUGA delivery:Required Product Fields:
  • UPC - 12 or 13 digits (no ‘auto’ value)
  • Title - Album title (without version)
  • Display Artist - Primary artists (no featuring artists)
  • Release Date - Consumer street date (YYYY-MM-DD)
  • Label - Label name
  • Language - 2-letter ISO code (e.g., ‘en’, ‘es’)
Required DDEX Metadata:
  • catalogTier - One of: ‘Back’, ‘Mid’, ‘Front’, ‘Premium’
  • territories - Array of territory codes or [‘World’]
Auto-Generated Fields:
  • C-Line - Copyright line (year + copyright holder)
  • P-Line - Phonographic copyright line (year + sound recording owner)
Node.js
const productData = {
  title: 'Greatest Hits',
  upc: '012345678901',
  displayArtist: 'The Beatles',
  releaseDate: '1969-09-26',
  label: 'Apple Records',
  language: 'en',
  publisher: 'Apple Corps Ltd',
  copyright: 'Apple Corps Ltd',
  ddexMetadata: {
    catalogTier: 'Premium',
    territories: ['World']
  }
};
3

Create Product with Delivery Flag

Use the delivery flag feature to automatically queue FUGA delivery:
  • Node.js
  • Python
  • cURL
const response = await fetch('https://api.royalti.io/product', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    delivery: ['fuga-csv'], // Auto-queues FUGA delivery!
    ...productData
  })
});

const result = await response.json();
console.log('Product created and delivery queued:', result.data.id);
The delivery flag creates the product AND queues FUGA delivery in a single API call. The system automatically generates the CSV file and schedules the FTP upload.
4

Manual Delivery (Alternative)

Or deliver an existing product manually:
Node.js
const response = await fetch(`https://api.royalti.io/product/${productId}/deliveries`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    providers: ['fuga-csv-ftp'],
    scheduledAt: '2024-06-01T00:00:00Z', // Optional: schedule for later
    options: {
      includeCoverArt: true,
      audioFormat: 'wav' // or 'flac', 'mp3'
    }
  })
});
5

Monitor Delivery Status

Track delivery progress and webhook updates:
Node.js
// Get delivery status
const status = await fetch(
  `https://api.royalti.io/product/${productId}/deliveries/${deliveryId}`,
  {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  }
);

// Check delivery logs
const logs = await fetch(
  `https://api.royalti.io/ddex/delivery/logs/${deliveryId}`,
  {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  }
);
Delivery Statuses:
  • pending - Queued for delivery
  • processing - Uploading files to FTP
  • delivered - Successfully uploaded to FUGA
  • confirmed - FUGA acknowledged receipt
  • completed - Delivered to DSPs
  • failed - Delivery failed (check logs for errors)

CSV Metadata Format

FUGA uses a CSV template with 50+ fields for catalog metadata. The Royalti.io API automatically generates this CSV from your product and asset data.

Product-Level Fields (Album)

FieldRequiredFormatExample
Album titleText”Greatest Hits”
Album versionText”Deluxe Edition”
UPC12-13 digits”012345678901”
Primary artistsPipe-separated”Artist A | Artist B”
Release dateYYYY-MM-DD”2024-06-01”
Main genreEnum”Pop”, “Rock”, “Hip Hop/Rap”
LabelText”XYZ Records”
C-Line yearYYYY”2024”
C-Line nameText”XYZ Records Inc”
P-Line yearYYYY”2024”
P-Line nameText”XYZ Records Inc”
Parental advisoryEnum”Yes”, “No”, “Clean”
Album formatEnum”Single”, “EP”, “Album”
Catalog TierEnum”Back”, “Mid”, “Front”, “Premium”
TerritoriesPipe-separated”World” or “US|CA|GB”

Track-Level Fields (Assets)

FieldRequiredFormatExample
Track titleText”Song Title”
ISRC12 chars (no dashes)“USRC12345678”
Track Primary artistsPipe-separated”Artist A”
Track Featuring ArtistsPipe-separated”Artist B | Artist C”
Volume numberInteger”1”
Track Main genreEnum”Pop”
Audio Language2-letter or ZXX”en” (ZXX = Instrumental)
Available separatelyY/N”Y”
Track SequenceInteger”1” (display order)
Track Catalog TierEnum”Front”
Original file nameText”012345678901_01_01.wav”
The API automatically formats your product/asset data into FUGA’s CSV format. You don’t need to manually create CSV files.

FTP Upload

The delivery system automatically uploads files to FUGA’s FTP server in the following structure:
/{UPC}/
  ├── metadata.csv          (FUGA CSV file)
  ├── 012345678901_01_01.wav  (Audio files)
  ├── 012345678901_01_02.wav
  └── cover.jpg             (Album artwork)

Audio File Requirements

  • Formats: WAV (recommended), FLAC, MP3 (320kbps)
  • Sample Rate: 44.1kHz or 48kHz
  • Bit Depth: 16-bit or 24-bit (WAV/FLAC)
  • Naming: {UPC}_{volume}_{track}.{ext} (e.g., 012345678901_01_01.wav)

Cover Art Requirements

  • Format: JPG or PNG
  • Dimensions: Minimum 3000x3000 pixels (square)
  • File Size: Maximum 10MB
  • Color Mode: RGB

Webhook Integration

FUGA sends webhooks to notify you of delivery status updates. Configure your webhook endpoint to receive these events.

Webhook Events

Product State Events:
  • product_state - Product acceptance/rejection/processing status
Delivery Events:
  • delivery_completed - Product delivered to DSP
  • delivery_cancelled - Delivery cancelled by FUGA
  • delivery_rejected - Delivery rejected by DSP
Ingestion Events:
  • xml_ingestion - Metadata ingestion results

Webhook Security

FUGA secures webhooks using SHA3-256 signature verification with your configured webhook salt.
The Royalti.io API automatically verifies all incoming webhook signatures using your configured webhook salt. You don’t need to implement verification yourself.
What happens automatically:
  • Signature verification using SHA3-256
  • Replay attack prevention (rejects webhooks older than 5 minutes)
  • Duplicate detection (prevents processing the same webhook twice)
  • Delivery status updates
  • User notifications

Webhook Endpoint

Configure FUGA to send webhooks to:
https://api.royalti.io/webhook/fuga/{tenantId}
The API automatically:
  • Verifies SHA3-256 signature
  • Prevents replay attacks (5-minute timestamp window)
  • Detects duplicate webhooks
  • Updates delivery status
  • Sends notifications to users

Validation Requirements

Before delivery, the system validates your product:
  • Must be 12 or 13 digits
  • Cannot be ‘auto’ value
  • Leading zeros preserved
  • No special characters
  • Must be 12 characters
  • No dashes or spaces
  • Format: XX-XXX-YY-NNNNN (stored without dashes)
  • Valid audio format (WAV, FLAC, MP3)
  • Minimum quality requirements met
  • File exists in storage
  • File size within limits
  • All required fields present
  • Genre from approved list
  • Valid territory codes
  • Parental advisory specified

Best Practices

Territory Management

Node.js
// Worldwide distribution
const territories = ['World'];

// Specific territories
const territories = ['US', 'CA', 'GB', 'DE', 'FR'];

// Exclusions (in DDEX metadata)
const ddexMetadata = {
  catalogTier: 'Front',
  territories: ['World'],
  excludedTerritories: ['CN', 'KP'] // Exclude specific countries
};

Catalog Tier Selection

  • Premium - New releases, major label artists
  • Front - Standard new releases
  • Mid - Catalog releases (1-5 years old)
  • Back - Older catalog (5+ years)

File Naming Convention

Node.js
// Recommended format: {UPC}_{volume}_{track}.{ext}
const fileName = `${product.upc}_${volume}_${trackNumber.toString().padStart(2, '0')}.wav`;
// Example: 012345678901_01_01.wav

Error Handling

Implement comprehensive validation and error handling:
Node.js
async function deliverToFuga(productId) {
  try {
    // Validate before delivery
    const validation = await fetch(
      `https://api.royalti.io/product/${productId}/deliveries/validate`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          providers: ['fuga-csv-ftp']
        })
      }
    );

    const validationResult = await validation.json();

    if (!validationResult.data.isValid) {
      console.error('Validation errors:', validationResult.data.errors);
      return { success: false, errors: validationResult.data.errors };
    }

    // Proceed with delivery
    const delivery = await fetch(
      `https://api.royalti.io/product/${productId}/deliveries`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          providers: ['fuga-csv-ftp']
        })
      }
    );

    const result = await delivery.json();

    return { success: true, deliveryId: result.data.id };

  } catch (error) {
    console.error('FUGA delivery failed:', error);
    throw error;
  }
}

Batch Delivery

Deliver multiple products simultaneously:
Node.js
const response = await fetch('https://api.royalti.io/product/batch-delivery', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    productIds: ['prod-1', 'prod-2', 'prod-3'],
    providers: ['fuga-csv-ftp'],
    options: {
      continueOnError: true, // Continue if individual deliveries fail
      notifyOnCompletion: true
    }
  })
});

Monitoring and Analytics

Health Metrics

Monitor FUGA delivery health:
Node.js
const metrics = await fetch('https://api.royalti.io/api/monitoring/fuga/metrics', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

// Returns:
// {
//   totalDeliveries: 150,
//   successfulDeliveries: 142,
//   failedDeliveries: 8,
//   averageUploadTime: 245000, // milliseconds
//   successRate: 94.67,
//   lastDeliveryAt: "2024-05-15T14:32:00Z"
// }

FTP Connection Health

Check FTP connectivity:
Node.js
const health = await fetch('https://api.royalti.io/api/monitoring/fuga/ftp-health', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Stuck Deliveries

Find deliveries that need attention:
Node.js
const stuck = await fetch('https://api.royalti.io/api/monitoring/fuga/stuck-deliveries', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Troubleshooting

Possible causes:
  • Queue processor not running
  • FTP credentials invalid
  • Rate limit exceeded
Solution:
// Retry delivery
await fetch(`https://api.royalti.io/product/${productId}/deliveries/${deliveryId}/retry`, {
  method: 'PUT',
  headers: { 'Authorization': `Bearer ${token}` }
});
Error: “Product has invalid UPC format for FUGA delivery”Solution:
  • Ensure UPC is 12 or 13 digits
  • Remove any dashes or spaces
  • UPC cannot be ‘auto’ - generate a real UPC
  • Preserve leading zeros
// Correct format
upc: '012345678901' // 12 digits with leading zero

// Incorrect formats
upc: 'auto'         // Not allowed
upc: '0123-4567-890' // No dashes
upc: '12345678901'  // Should preserve leading zero
Error: “Original file name must exist on FTP server”Solution:
  • Ensure audio files are uploaded to storage
  • Verify file naming matches CSV metadata
  • Check file format is supported (WAV, FLAC, MP3)
Error: “Invalid webhook signature”Solution:
  • Verify webhook salt matches FUGA configuration
  • Check salt is stored in provider credentials
  • Ensure webhook timestamp is recent (< 5 minutes)