> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.royalti.io/llms.txt
> Use this file to discover all available pages before exploring further.

# FUGA Integration Guide

> Deliver music catalog to DSPs via FUGA's CSV/FTP distribution platform

## 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

<Note>
  FUGA delivery endpoints require authentication and the "DDEX & Deliveries" addon to be enabled.
</Note>

## FUGA Workflow

<Steps>
  <Step title="Configure FUGA Provider">
    Set up your FUGA FTP credentials and webhook salt for delivery tracking.

    <Tabs>
      <Tab title="Node.js">
        ```javascript theme={null}
        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);
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        import requests

        response = requests.post(
            'https://api.royalti.io/ddex/tenant-providers',
            headers={
                'Authorization': f'Bearer {token}',
                'Content-Type': 'application/json'
            },
            json={
                'providerId': 'fuga-csv-ftp',
                'credentials': {
                    'host': 'ftp.fuga.com',
                    'username': 'your-username',
                    'password': 'your-password',
                    'port': 21,
                    'webhookSalt': 'your-webhook-salt'
                },
                'isActive': True
            }
        )

        result = response.json()
        print(f"Provider configured: {result['data']['id']}")
        ```
      </Tab>

      <Tab title="cURL">
        ```bash theme={null}
        curl -X POST https://api.royalti.io/ddex/tenant-providers \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "providerId": "fuga-csv-ftp",
            "credentials": {
              "host": "ftp.fuga.com",
              "username": "your-username",
              "password": "your-password",
              "port": 21,
              "webhookSalt": "your-webhook-salt"
            },
            "isActive": true
          }'
        ```
      </Tab>
    </Tabs>

    <Info>
      All FTP credentials and webhook salts are automatically encrypted at rest. No plaintext credentials are stored in the database.
    </Info>
  </Step>

  <Step title="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']

    **Copyright Line Fields:**

    * **c\_line\_year** - Copyright year (©) - defaults to current year if not provided
    * **p\_line\_year** - Phonogram year (℗) - defaults to current year if not provided
    * **copyright** - Copyright holder name for C-Line
    * **publisher** - Sound recording owner for P-Line

    <Info>
      If `c_line_year` or `p_line_year` are not provided, the system automatically uses the current year. For reissues, you should explicitly set these to the original release year.
    </Info>

    ```javascript Node.js theme={null}
    const productData = {
      title: 'Greatest Hits',
      upc: '012345678901',
      displayArtist: 'The Beatles',
      releaseDate: '1969-09-26',
      label: 'Apple Records',
      language: 'en',
      
      // Copyright fields
      publisher: 'Apple Corps Ltd',
      copyright: 'Apple Corps Ltd',
      c_line_year: 1969,  // Year for © line
      p_line_year: 1969,  // Year for ℗ line
      
      // For reissues
      reissue: true,
      originalReleaseDate: '1969-09-26',
      edition: 'Remastered',
      
      ddexMetadata: {
        catalogTier: 'Premium',
        territories: ['World']
      }
    };
    ```

    **Reissue Example:**

    ```javascript Node.js theme={null}
    // For a 2024 remaster of a 1969 album
    const reissueData = {
      title: 'Abbey Road',
      upc: '012345678902',
      displayArtist: 'The Beatles',
      releaseDate: '2024-09-26',      // New release date
      originalReleaseDate: '1969-09-26', // Original release
      reissue: true,
      edition: '2024 Remaster',
      label: 'Apple Records',
      language: 'en',
      copyright: 'Apple Corps Ltd',
      publisher: 'Apple Corps Ltd',
      c_line_year: 2024,  // New copyright for remaster
      p_line_year: 1969,  // Original phonogram year
      ddexMetadata: {
        catalogTier: 'Premium',
        territories: ['World']
      }
    };
    ```
  </Step>

  <Step title="Create Product with Delivery Flag">
    Use the delivery flag feature to automatically queue FUGA delivery:

    <Tabs>
      <Tab title="Node.js">
        ```javascript theme={null}
        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);
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        response = requests.post(
            'https://api.royalti.io/product',
            headers={
                'Authorization': f'Bearer {token}',
                'Content-Type': 'application/json'
            },
            json={
                'delivery': ['fuga-csv'],
                **product_data
            }
        )

        result = response.json()
        print(f"Product created: {result['data']['id']}")
        ```
      </Tab>

      <Tab title="cURL">
        ```bash theme={null}
        curl -X POST https://api.royalti.io/product \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "delivery": ["fuga-csv"],
            "title": "Greatest Hits",
            "upc": "012345678901",
            "displayArtist": "The Beatles",
            "releaseDate": "1969-09-26",
            "label": "Apple Records",
            "language": "en",
            "ddexMetadata": {
              "catalogTier": "Premium",
              "territories": ["World"]
            }
          }'
        ```
      </Tab>
    </Tabs>

    <Note>
      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.
    </Note>
  </Step>

  <Step title="Manual Delivery (Alternative)">
    Or deliver an existing product manually:

    ```javascript Node.js theme={null}
    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'
        }
      })
    });
    ```
  </Step>

  <Step title="Monitor Delivery Status">
    Track delivery progress and webhook updates:

    ```javascript Node.js theme={null}
    // 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)
  </Step>
</Steps>

## 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)

| FUGA CSV Field    | API Field                  | Required | Format         | Example                           |
| ----------------- | -------------------------- | -------- | -------------- | --------------------------------- |
| Album title       | `title`                    | ✓        | Text           | "Greatest Hits"                   |
| Album version     | `edition`                  |          | Text           | "Deluxe Edition"                  |
| UPC               | `upc`                      | ✓        | 12-13 digits   | "012345678901"                    |
| Primary artists   | `displayArtist`            | ✓        | Pipe-separated | "Artist A \| Artist B"            |
| Release date      | `releaseDate`              | ✓        | YYYY-MM-DD     | "2024-06-01"                      |
| Main genre        | `mainGenre`                | ✓        | Enum           | "Pop", "Rock", "Hip Hop/Rap"      |
| Label             | `label`                    | ✓        | Text           | "XYZ Records"                     |
| C-Line year       | `c_line_year`              | ✓        | YYYY           | "2024"                            |
| C-Line name       | `copyright`                | ✓        | Text           | "XYZ Records Inc"                 |
| P-Line year       | `p_line_year`              | ✓        | YYYY           | "2024"                            |
| P-Line name       | `publisher`                | ✓        | Text           | "XYZ Records Inc"                 |
| Parental advisory | `explicit`                 | ✓        | Enum           | "Yes", "No", "Clean"              |
| Album format      | `format`                   | ✓        | Enum           | "Single", "EP", "Album"           |
| Catalog Tier      | `ddexMetadata.catalogTier` | ✓        | Enum           | "Back", "Mid", "Front", "Premium" |
| Territories       | `ddexMetadata.territories` |          | Pipe-separated | "World" or "US\|CA\|GB"           |

<Note>
  The API automatically maps your product fields to FUGA's CSV format. Fields like `c_line_year` and `p_line_year` default to the current year if not provided.
</Note>

### Track-Level Fields (Assets)

| Field                   | Required | Format               | Example                    |
| ----------------------- | -------- | -------------------- | -------------------------- |
| Track title             | ✓        | Text                 | "Song Title"               |
| ISRC                    | ✓        | 12 chars (no dashes) | "USRC12345678"             |
| Track Primary artists   | ✓        | Pipe-separated       | "Artist A"                 |
| Track Featuring Artists |          | Pipe-separated       | "Artist B \| Artist C"     |
| Volume number           | ✓        | Integer              | "1"                        |
| Track Main genre        | ✓        | Enum                 | "Pop"                      |
| Audio Language          | ✓        | 2-letter or ZXX      | "en" (ZXX = Instrumental)  |
| Available separately    | ✓        | Y/N                  | "Y"                        |
| Track Sequence          | ✓        | Integer              | "1" (display order)        |
| Track Catalog Tier      | ✓        | Enum                 | "Front"                    |
| Original file name      | ✓        | Text                 | "012345678901\_01\_01.wav" |

<Info>
  The API automatically formats your product/asset data into FUGA's CSV format. You don't need to manually create CSV files.
</Info>

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

<Warning>
  The Royalti.io API automatically verifies all incoming webhook signatures using your configured webhook salt. You don't need to implement verification yourself.
</Warning>

**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:

<AccordionGroup>
  <Accordion title="UPC Validation">
    * Must be 12 or 13 digits
    * Cannot be 'auto' value
    * Leading zeros preserved
    * No special characters
  </Accordion>

  <Accordion title="ISRC Validation">
    * Must be 12 characters
    * No dashes or spaces
    * Format: XX-XXX-YY-NNNNN (stored without dashes)
  </Accordion>

  <Accordion title="Audio File Validation">
    * Valid audio format (WAV, FLAC, MP3)
    * Minimum quality requirements met
    * File exists in storage
    * File size within limits
  </Accordion>

  <Accordion title="Metadata Completeness">
    * All required fields present
    * Genre from approved list
    * Valid territory codes
    * Parental advisory specified
  </Accordion>
</AccordionGroup>

## Best Practices

### Territory Management

```javascript Node.js theme={null}
// 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

```javascript Node.js theme={null}
// 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:

```javascript Node.js theme={null}
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:

```javascript Node.js theme={null}
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:

```javascript Node.js theme={null}
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:

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

### Stuck Deliveries

Find deliveries that need attention:

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

## Troubleshooting

<AccordionGroup>
  <Accordion title="Delivery stuck in 'pending' status">
    **Possible causes:**

    * Queue processor not running
    * FTP credentials invalid
    * Rate limit exceeded

    **Solution:**

    ```javascript theme={null}
    // Retry delivery
    await fetch(`https://api.royalti.io/product/${productId}/deliveries/${deliveryId}/retry`, {
      method: 'PUT',
      headers: { 'Authorization': `Bearer ${token}` }
    });
    ```
  </Accordion>

  <Accordion title="UPC validation error">
    **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

    ```javascript theme={null}
    // 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
    ```
  </Accordion>

  <Accordion title="Audio file not found">
    **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)
  </Accordion>

  <Accordion title="Webhook signature verification failed">
    **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)
  </Accordion>
</AccordionGroup>

## Related Endpoints

* [Create Product Delivery](/api-reference/fuga-delivery/post-product-id-deliveries)
* [Validate Product Delivery](/api-reference/fuga-delivery/post-product-id-deliveries-validate)
* [Batch Product Delivery](/api-reference/fuga-delivery/batch-product-delivery)
* [Get Delivery Status](/api-reference/fuga-delivery/get-product-id-deliveries-id)
* [Retry Failed Delivery](/api-reference/fuga-delivery/put-product-id-deliveries-id-retry)
* [FUGA Monitoring Metrics](/api-reference/fuga-delivery/get-api-monitoring-fuga-metrics)
* [Configure DDEX Provider](/api-reference/ddex/post-ddex-tenant-providers)
