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

# Asset DDEX Management

> Complete guide to managing DDEX metadata and ensuring delivery readiness for your audio assets

## Overview

DDEX (Digital Data Exchange) is the industry standard for exchanging music metadata between parties in the music industry. Proper DDEX metadata is essential for delivering your products to Digital Service Providers (DSPs).

This guide covers how to:

* Update DDEX metadata for your assets
* Validate asset DDEX readiness
* Prepare assets for product delivery
* Troubleshoot common DDEX issues

## Quick Start

<Steps>
  <Step title="Update Asset DDEX Metadata">
    Add or update DDEX-compliant metadata for your audio asset.

    <Tabs>
      <Tab title="cURL">
        ```bash theme={null}
        curl -X PUT https://api.royalti.io/asset/asset_123/ddex-metadata \
          -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "ddexMetadata": {
              "resourceReference": "A123456789",
              "title": "My Song Title",
              "displayArtist": "Artist Name",
              "languageOfPerformance": "en",
              "duration": "PT3M45S",
              "parentalWarningType": "NotExplicit"
            },
            "technicalResourceDetails": {
              "fileFormat": "WAV",
              "sampleRate": 44100,
              "bitDepth": 16,
              "numberOfChannels": 2,
              "audioCodec": "PCM"
            },
            "soundRecordingDetails": {
              "isrc": "USRC17607839",
              "pLine": {
                "year": 2024,
                "pLineText": "2024 Record Label Name"
              },
              "genre": "Pop",
              "subGenre": "Indie Pop"
            }
          }'
        ```
      </Tab>

      <Tab title="Node.js">
        ```javascript theme={null}
        const axios = require('axios');

        async function updateAssetDDEX(assetId, ddexData) {
          try {
            const response = await axios.put(
              `https://api.royalti.io/asset/${assetId}/ddex-metadata`,
              {
                ddexMetadata: {
                  resourceReference: ddexData.resourceReference,
                  title: ddexData.title,
                  displayArtist: ddexData.displayArtist,
                  languageOfPerformance: ddexData.language || 'en',
                  duration: ddexData.duration, // ISO 8601 format: PT3M45S
                  parentalWarningType: ddexData.explicit ? 'Explicit' : 'NotExplicit'
                },
                technicalResourceDetails: {
                  fileFormat: ddexData.format || 'WAV',
                  sampleRate: ddexData.sampleRate || 44100,
                  bitDepth: ddexData.bitDepth || 16,
                  numberOfChannels: ddexData.channels || 2,
                  audioCodec: ddexData.codec || 'PCM'
                },
                soundRecordingDetails: {
                  isrc: ddexData.isrc,
                  pLine: {
                    year: new Date().getFullYear(),
                    pLineText: ddexData.pLine
                  },
                  genre: ddexData.genre,
                  subGenre: ddexData.subGenre
                }
              },
              {
                headers: {
                  'Authorization': `Bearer ${process.env.ROYALTI_ACCESS_TOKEN}`,
                  'Content-Type': 'application/json'
                }
              }
            );

            console.log('DDEX metadata updated:', response.data);
            return response.data;
          } catch (error) {
            console.error('Failed to update DDEX metadata:', error.response?.data);
            throw error;
          }
        }

        // Example usage
        updateAssetDDEX('asset_123', {
          resourceReference: 'A123456789',
          title: 'My Song Title',
          displayArtist: 'Artist Name',
          language: 'en',
          duration: 'PT3M45S',
          explicit: false,
          isrc: 'USRC17607839',
          pLine: '2024 Record Label Name',
          genre: 'Pop',
          subGenre: 'Indie Pop'
        });
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        import requests
        from datetime import datetime

        def update_asset_ddex(asset_id, ddex_data):
            """Update DDEX metadata for an asset"""
            url = f"https://api.royalti.io/asset/{asset_id}/ddex-metadata"

            payload = {
                "ddexMetadata": {
                    "resourceReference": ddex_data["resource_reference"],
                    "title": ddex_data["title"],
                    "displayArtist": ddex_data["display_artist"],
                    "languageOfPerformance": ddex_data.get("language", "en"),
                    "duration": ddex_data["duration"],  # ISO 8601: PT3M45S
                    "parentalWarningType": "Explicit" if ddex_data.get("explicit") else "NotExplicit"
                },
                "technicalResourceDetails": {
                    "fileFormat": ddex_data.get("format", "WAV"),
                    "sampleRate": ddex_data.get("sample_rate", 44100),
                    "bitDepth": ddex_data.get("bit_depth", 16),
                    "numberOfChannels": ddex_data.get("channels", 2),
                    "audioCodec": ddex_data.get("codec", "PCM")
                },
                "soundRecordingDetails": {
                    "isrc": ddex_data["isrc"],
                    "pLine": {
                        "year": datetime.now().year,
                        "pLineText": ddex_data["p_line"]
                    },
                    "genre": ddex_data["genre"],
                    "subGenre": ddex_data.get("sub_genre")
                }
            }

            headers = {
                "Authorization": f"Bearer {os.getenv('ROYALTI_ACCESS_TOKEN')}",
                "Content-Type": "application/json"
            }

            response = requests.put(url, json=payload, headers=headers)
            response.raise_for_status()

            print(f"DDEX metadata updated: {response.json()}")
            return response.json()

        # Example usage
        update_asset_ddex('asset_123', {
            'resource_reference': 'A123456789',
            'title': 'My Song Title',
            'display_artist': 'Artist Name',
            'language': 'en',
            'duration': 'PT3M45S',
            'explicit': False,
            'isrc': 'USRC17607839',
            'p_line': '2024 Record Label Name',
            'genre': 'Pop',
            'sub_genre': 'Indie Pop'
        })
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Check Asset DDEX Readiness">
    Validate that your asset has all required DDEX metadata before delivery.

    <Tabs>
      <Tab title="cURL">
        ```bash theme={null}
        curl -X GET https://api.royalti.io/asset/asset_123/ddex-readiness \
          -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
        ```
      </Tab>

      <Tab title="Node.js">
        ```javascript theme={null}
        async function checkDDEXReadiness(assetId) {
          try {
            const response = await axios.get(
              `https://api.royalti.io/asset/${assetId}/ddex-readiness`,
              {
                headers: {
                  'Authorization': `Bearer ${process.env.ROYALTI_ACCESS_TOKEN}`
                }
              }
            );

            const { isReady, readinessScore, missingFields, invalidFields, warnings } = response.data.data;

            if (isReady) {
              console.log(`✓ Asset is DDEX ready (score: ${readinessScore}%)`);
            } else {
              console.log(`✗ Asset is NOT ready (score: ${readinessScore}%)`);
              if (missingFields.length > 0) {
                console.log('Missing fields:', missingFields);
              }
              if (invalidFields.length > 0) {
                console.log('Invalid fields:', invalidFields);
              }
              if (warnings.length > 0) {
                console.log('Warnings:', warnings);
              }
            }

            return response.data.data;
          } catch (error) {
            console.error('Failed to check DDEX readiness:', error.response?.data);
            throw error;
          }
        }

        checkDDEXReadiness('asset_123');
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        def check_ddex_readiness(asset_id):
            """Check if asset is ready for DDEX delivery"""
            url = f"https://api.royalti.io/asset/{asset_id}/ddex-readiness"

            headers = {
                "Authorization": f"Bearer {os.getenv('ROYALTI_ACCESS_TOKEN')}"
            }

            response = requests.get(url, headers=headers)
            response.raise_for_status()

            data = response.json()["data"]

            if data["isReady"]:
                print(f"✓ Asset is DDEX ready (score: {data['readinessScore']}%)")
            else:
                print(f"✗ Asset is NOT ready (score: {data['readinessScore']}%)")
                if data["missingFields"]:
                    print(f"Missing fields: {data['missingFields']}")
                if data["invalidFields"]:
                    print(f"Invalid fields: {data['invalidFields']}")
                if data["warnings"]:
                    print(f"Warnings: {data['warnings']}")

            return data

        check_ddex_readiness('asset_123')
        ```
      </Tab>
    </Tabs>

    <Note>
      A readiness score of 100% is required for delivery. Scores below 100% indicate missing or invalid fields.
    </Note>
  </Step>

  <Step title="Review and Fix Issues">
    Address any missing or invalid fields identified in the readiness check.

    ```json theme={null}
    {
      "status": "success",
      "data": {
        "isReady": false,
        "readinessScore": 75,
        "missingFields": [
          "soundRecordingDetails.isrc",
          "ddexMetadata.duration"
        ],
        "invalidFields": [
          {
            "field": "technicalResourceDetails.sampleRate",
            "issue": "Must be 44100 or 48000",
            "currentValue": 22050
          }
        ],
        "warnings": [
          "Genre 'Unknown' may not be recognized by all DSPs"
        ],
        "suggestions": [
          "Add ISRC code for proper identification",
          "Update sample rate to 44100 Hz or 48000 Hz",
          "Specify a standard genre from the approved list"
        ]
      }
    }
    ```

    Update your asset metadata to address each issue, then re-check readiness.
  </Step>

  <Step title="Integrate with Product Delivery">
    Once your asset is DDEX ready, you can include it in product deliveries.

    See the [Product Delivery Guide](/guides/product-delivery) for complete delivery workflows.
  </Step>
</Steps>

## DDEX Metadata Structure

### Resource Reference

Unique identifier for the audio resource within your catalog.

```json theme={null}
{
  "resourceReference": "A123456789"
}
```

<Tip>
  Use a consistent naming scheme for resource references (e.g., prefix + sequential number).
</Tip>

### Basic Metadata

Core information about the recording.

```json theme={null}
{
  "title": "Song Title",
  "displayArtist": "Artist Name",
  "languageOfPerformance": "en",
  "duration": "PT3M45S",
  "parentalWarningType": "NotExplicit"
}
```

**Duration Format**: ISO 8601 duration (e.g., `PT3M45S` = 3 minutes 45 seconds)

**Parental Warning Types**:

* `NotExplicit` - Clean content
* `Explicit` - Contains explicit content
* `Unknown` - Warning status unknown

**Language Codes**: ISO 639-1 two-letter codes (e.g., `en`, `es`, `fr`, `de`, `ja`)

### Technical Resource Details

Audio file specifications required for delivery.

```json theme={null}
{
  "fileFormat": "WAV",
  "sampleRate": 44100,
  "bitDepth": 16,
  "numberOfChannels": 2,
  "audioCodec": "PCM"
}
```

**Accepted Sample Rates**: 44100 Hz, 48000 Hz, 96000 Hz

**Accepted Bit Depths**: 16-bit, 24-bit

**Supported Formats**:

* WAV (recommended)
* FLAC
* AIFF

### Sound Recording Details

Metadata specific to the sound recording.

```json theme={null}
{
  "isrc": "USRC17607839",
  "pLine": {
    "year": 2024,
    "pLineText": "2024 Record Label Name"
  },
  "genre": "Pop",
  "subGenre": "Indie Pop"
}
```

**ISRC**: International Standard Recording Code (12 characters: 2-letter country + 3-char registrant + 2-digit year + 5-digit designation)

**Genre Standards**: Use recognized genre names from the DDEX genre list for best DSP compatibility.

## Readiness Validation

### Readiness Score Calculation

The readiness score is calculated based on:

* **Required fields** (60%): ISRC, duration, title, artist, format, sample rate
* **Recommended fields** (30%): Genre, language, P-line, parental warning
* **Technical quality** (10%): Valid sample rate/bit depth, proper format

### Common Validation Issues

<AccordionGroup>
  <Accordion title="Missing ISRC Code">
    **Error**: `soundRecordingDetails.isrc is required`

    **Cause**: ISRC (International Standard Recording Code) is mandatory for DSP delivery.

    **Solution**: Generate or obtain an ISRC code for your recording:

    <Tabs>
      <Tab title="Node.js">
        ```javascript theme={null}
        // If you have an ISRC
        const ddexData = {
          soundRecordingDetails: {
            isrc: 'USRC17607839'
          }
        };

        // If you need to generate one (contact your national ISRC agency)
        // Format: CC-XXX-YY-NNNNN
        // CC = Country code (e.g., US)
        // XXX = Registrant code
        // YY = Year
        // NNNNN = Designation code
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        # If you have an ISRC
        ddex_data = {
            'soundRecordingDetails': {
                'isrc': 'USRC17607839'
            }
        }

        # Format validation
        import re
        def validate_isrc(isrc):
            pattern = r'^[A-Z]{2}[A-Z0-9]{3}\d{7}$'
            return bool(re.match(pattern, isrc))
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Invalid Duration Format">
    **Error**: `ddexMetadata.duration must be in ISO 8601 format`

    **Cause**: Duration must be specified in ISO 8601 format (e.g., `PT3M45S`).

    **Solution**: Convert your duration to ISO 8601 format:

    <Tabs>
      <Tab title="Node.js">
        ```javascript theme={null}
        function secondsToISO8601(seconds) {
          const hours = Math.floor(seconds / 3600);
          const minutes = Math.floor((seconds % 3600) / 60);
          const secs = Math.floor(seconds % 60);

          let duration = 'PT';
          if (hours > 0) duration += `${hours}H`;
          if (minutes > 0) duration += `${minutes}M`;
          if (secs > 0) duration += `${secs}S`;

          return duration;
        }

        // Example: 225 seconds = 3 minutes 45 seconds
        const duration = secondsToISO8601(225); // "PT3M45S"
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        from datetime import timedelta

        def seconds_to_iso8601(seconds):
            """Convert seconds to ISO 8601 duration format"""
            td = timedelta(seconds=seconds)
            hours = td.seconds // 3600
            minutes = (td.seconds % 3600) // 60
            secs = td.seconds % 60

            parts = ['PT']
            if hours > 0:
                parts.append(f'{hours}H')
            if minutes > 0:
                parts.append(f'{minutes}M')
            if secs > 0:
                parts.append(f'{secs}S')

            return ''.join(parts)

        # Example: 225 seconds = 3 minutes 45 seconds
        duration = seconds_to_iso8601(225)  # "PT3M45S"
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Invalid Sample Rate">
    **Error**: `technicalResourceDetails.sampleRate must be 44100, 48000, or 96000`

    **Cause**: DSPs require specific sample rates for audio delivery.

    **Solution**: Re-encode your audio file at an accepted sample rate (44.1 kHz recommended):

    ```bash theme={null}
    # Using ffmpeg to convert sample rate
    ffmpeg -i input.wav -ar 44100 -sample_fmt s16 output.wav
    ```

    Then update your metadata:

    ```json theme={null}
    {
      "technicalResourceDetails": {
        "sampleRate": 44100,
        "bitDepth": 16
      }
    }
    ```
  </Accordion>

  <Accordion title="Missing P-Line Information">
    **Error**: `soundRecordingDetails.pLine is recommended`

    **Cause**: P-Line (phonographic copyright) is recommended for proper rights attribution.

    **Solution**: Add P-Line information:

    ```json theme={null}
    {
      "soundRecordingDetails": {
        "pLine": {
          "year": 2024,
          "pLineText": "2024 Your Record Label Name"
        }
      }
    }
    ```

    <Note>
      P-Line year should be the year of first publication, not the current year.
    </Note>
  </Accordion>

  <Accordion title="Unrecognized Genre">
    **Warning**: `Genre 'Unknown' may not be recognized by all DSPs`

    **Cause**: Using non-standard or generic genre names.

    **Solution**: Use standard DDEX genre classifications:

    **Primary Genres**:

    * Alternative
    * Blues
    * Children's Music
    * Classical
    * Comedy
    * Country
    * Dance
    * Electronic
    * Folk
    * Hip-Hop/Rap
    * Jazz
    * Latin
    * Pop
    * R\&B/Soul
    * Reggae
    * Rock
    * Soundtrack
    * World

    **Example**:

    ```json theme={null}
    {
      "soundRecordingDetails": {
        "genre": "Electronic",
        "subGenre": "House"
      }
    }
    ```
  </Accordion>

  <Accordion title="Missing Musical Work Reference">
    **Warning**: `musicalWorkReference is recommended for publishing metadata`

    **Cause**: No link between the sound recording and the underlying musical work.

    **Solution**: Add musical work reference if you have publishing information:

    ```json theme={null}
    {
      "musicalWorkReference": {
        "workId": "work_456",
        "iswc": "T-123.456.789-0",
        "composers": ["Composer Name"],
        "publishers": ["Publisher Name"]
      }
    }
    ```

    <Tip>
      ISWC (International Standard Musical Work Code) helps with publishing royalty collection.
    </Tip>
  </Accordion>
</AccordionGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Validate Early" icon="check-circle">
    Check DDEX readiness before creating products to catch issues early in your workflow.
  </Card>

  <Card title="Use High-Quality Audio" icon="waveform">
    Upload lossless formats (WAV, FLAC) at 44.1 kHz or higher for best quality across all DSPs.
  </Card>

  <Card title="Maintain Metadata Consistency" icon="database">
    Keep asset metadata synchronized with your product metadata for smooth delivery.
  </Card>

  <Card title="Monitor Readiness Scores" icon="chart-line">
    Aim for 100% readiness scores to ensure compatibility with all delivery providers.
  </Card>
</CardGroup>

## Complete Integration Example

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    const axios = require('axios');

    class DDEXAssetManager {
      constructor(accessToken) {
        this.client = axios.create({
          baseURL: 'https://api.royalti.io',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
          }
        });
      }

      async updateAssetMetadata(assetId, metadata) {
        try {
          const response = await this.client.put(
            `/asset/${assetId}/ddex-metadata`,
            metadata
          );
          console.log(`✓ Updated DDEX metadata for ${assetId}`);
          return response.data;
        } catch (error) {
          console.error('Failed to update metadata:', error.response?.data);
          throw error;
        }
      }

      async checkReadiness(assetId) {
        try {
          const response = await this.client.get(
            `/asset/${assetId}/ddex-readiness`
          );
          return response.data.data;
        } catch (error) {
          console.error('Failed to check readiness:', error.response?.data);
          throw error;
        }
      }

      async ensureAssetReady(assetId, metadata) {
        // Step 1: Update metadata
        await this.updateAssetMetadata(assetId, metadata);

        // Step 2: Check readiness
        const readiness = await this.checkReadiness(assetId);

        // Step 3: Report results
        if (readiness.isReady) {
          console.log(`✓ Asset ${assetId} is ready (score: ${readiness.readinessScore}%)`);
          return true;
        } else {
          console.log(`✗ Asset ${assetId} is NOT ready (score: ${readiness.readinessScore}%)`);

          if (readiness.missingFields.length > 0) {
            console.log('\nMissing fields:');
            readiness.missingFields.forEach(field => {
              console.log(`  - ${field}`);
            });
          }

          if (readiness.invalidFields.length > 0) {
            console.log('\nInvalid fields:');
            readiness.invalidFields.forEach(({ field, issue, currentValue }) => {
              console.log(`  - ${field}: ${issue} (current: ${currentValue})`);
            });
          }

          if (readiness.suggestions.length > 0) {
            console.log('\nSuggestions:');
            readiness.suggestions.forEach(suggestion => {
              console.log(`  - ${suggestion}`);
            });
          }

          return false;
        }
      }
    }

    // Example usage
    async function prepareAssetForDelivery() {
      const manager = new DDEXAssetManager(process.env.ROYALTI_ACCESS_TOKEN);

      const assetMetadata = {
        ddexMetadata: {
          resourceReference: 'A123456789',
          title: 'My New Single',
          displayArtist: 'The Artist',
          languageOfPerformance: 'en',
          duration: 'PT3M45S',
          parentalWarningType: 'NotExplicit'
        },
        technicalResourceDetails: {
          fileFormat: 'WAV',
          sampleRate: 44100,
          bitDepth: 16,
          numberOfChannels: 2,
          audioCodec: 'PCM'
        },
        soundRecordingDetails: {
          isrc: 'USRC17607839',
          pLine: {
            year: 2024,
            pLineText: '2024 Independent Records'
          },
          genre: 'Pop',
          subGenre: 'Indie Pop'
        }
      };

      const isReady = await manager.ensureAssetReady('asset_123', assetMetadata);

      if (isReady) {
        console.log('\n✓ Asset is ready for product delivery!');
        // Proceed with product delivery workflow
      } else {
        console.log('\n✗ Please fix the issues above before delivery');
      }
    }

    prepareAssetForDelivery().catch(console.error);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests
    import os
    from typing import Dict, Any, List

    class DDEXAssetManager:
        def __init__(self, access_token: str):
            self.base_url = 'https://api.royalti.io'
            self.headers = {
                'Authorization': f'Bearer {access_token}',
                'Content-Type': 'application/json'
            }

        def update_asset_metadata(self, asset_id: str, metadata: Dict[str, Any]) -> Dict:
            """Update DDEX metadata for an asset"""
            url = f'{self.base_url}/asset/{asset_id}/ddex-metadata'
            response = requests.put(url, json=metadata, headers=self.headers)
            response.raise_for_status()
            print(f'✓ Updated DDEX metadata for {asset_id}')
            return response.json()

        def check_readiness(self, asset_id: str) -> Dict[str, Any]:
            """Check asset DDEX readiness"""
            url = f'{self.base_url}/asset/{asset_id}/ddex-readiness'
            response = requests.get(url, headers=self.headers)
            response.raise_for_status()
            return response.json()['data']

        def ensure_asset_ready(self, asset_id: str, metadata: Dict[str, Any]) -> bool:
            """Update metadata and verify asset is ready for delivery"""

            # Step 1: Update metadata
            self.update_asset_metadata(asset_id, metadata)

            # Step 2: Check readiness
            readiness = self.check_readiness(asset_id)

            # Step 3: Report results
            if readiness['isReady']:
                print(f"✓ Asset {asset_id} is ready (score: {readiness['readinessScore']}%)")
                return True
            else:
                print(f"✗ Asset {asset_id} is NOT ready (score: {readiness['readinessScore']}%)")

                if readiness['missingFields']:
                    print('\nMissing fields:')
                    for field in readiness['missingFields']:
                        print(f'  - {field}')

                if readiness['invalidFields']:
                    print('\nInvalid fields:')
                    for item in readiness['invalidFields']:
                        print(f"  - {item['field']}: {item['issue']} (current: {item['currentValue']})")

                if readiness['suggestions']:
                    print('\nSuggestions:')
                    for suggestion in readiness['suggestions']:
                        print(f'  - {suggestion}')

                return False

    # Example usage
    def prepare_asset_for_delivery():
        """Complete workflow to prepare asset for DDEX delivery"""
        manager = DDEXAssetManager(os.getenv('ROYALTI_ACCESS_TOKEN'))

        asset_metadata = {
            'ddexMetadata': {
                'resourceReference': 'A123456789',
                'title': 'My New Single',
                'displayArtist': 'The Artist',
                'languageOfPerformance': 'en',
                'duration': 'PT3M45S',
                'parentalWarningType': 'NotExplicit'
            },
            'technicalResourceDetails': {
                'fileFormat': 'WAV',
                'sampleRate': 44100,
                'bitDepth': 16,
                'numberOfChannels': 2,
                'audioCodec': 'PCM'
            },
            'soundRecordingDetails': {
                'isrc': 'USRC17607839',
                'pLine': {
                    'year': 2024,
                    'pLineText': '2024 Independent Records'
                },
                'genre': 'Pop',
                'subGenre': 'Indie Pop'
            }
        }

        is_ready = manager.ensure_asset_ready('asset_123', asset_metadata)

        if is_ready:
            print('\n✓ Asset is ready for product delivery!')
            # Proceed with product delivery workflow
        else:
            print('\n✗ Please fix the issues above before delivery')

    if __name__ == '__main__':
        prepare_asset_for_delivery()
    ```
  </Tab>
</Tabs>

## Delivery Workflow Integration

```mermaid theme={null}
graph LR
    A[Upload Asset] --> B[Update DDEX Metadata]
    B --> C[Check Readiness]
    C --> D{Ready?}
    D -->|Yes| E[Create Product]
    D -->|No| F[Fix Issues]
    F --> B
    E --> G[Validate Product]
    G --> H[Deliver to DSPs]
```

Once your assets are DDEX ready:

1. Create a product with your DDEX-ready assets
2. Validate the product for delivery
3. Deliver to DSPs using the [Product Delivery API](/guides/product-delivery)

## Related Resources

<CardGroup cols={2}>
  <Card title="Product Delivery" icon="rocket" href="/guides/product-delivery">
    Learn how to deliver products to DSPs
  </Card>

  <Card title="Asset API Reference" icon="code" href="/api-reference/asset/put-asset-id-ddex-metadata">
    Complete API documentation for asset endpoints
  </Card>

  <Card title="DDEX Standards" icon="book" href="https://ddex.net" target="_blank">
    Official DDEX documentation and standards
  </Card>

  <Card title="ISRC Registration" icon="id-card" href="https://usisrc.org" target="_blank">
    Register for ISRC codes (US)
  </Card>
</CardGroup>
