
DDEX (Digital Data Exchange) is a set of international standards for exchanging digital media data in the music industry. These XML-based standards ensure that information about releases, licensing, recordings, and sales flows accurately between creators, distributors, and retailers.
The most common use case today is proving rights to a piece of music (clearance) or sending takedown messages when content is used without permission. Different content providers support different DDEX versions — YouTube supports 3.4 to 3.8, Facebook supports 3.8.3, and the newest version is 4.2.
The simplest approach is to start from an existing DDEX file and create a template. Octolivery is one of the few DDEX file generators available.
To fill the template, you'll need:
Here's a minimal example using Python's built-in xml.etree.ElementTree to create a DDEX ERN file:
import xml.etree.ElementTree as ET
# Create root element
root = ET.Element("ern:NewReleaseMessage", {
"xmlns:ern": "http://ddex.net/xml/ern/43",
"MessageSchemaVersionId": "ern/43",
})
# Message header
header = ET.SubElement(root, "MessageHeader")
ET.SubElement(header, "MessageId").text = "MSG-2023-001"
ET.SubElement(header, "MessageCreatedDateTime").text = "2023-12-07T10:00:00Z"
sender = ET.SubElement(header, "MessageSender")
ET.SubElement(sender, "PartyId").text = "PADPIDA2023010101A"
ET.SubElement(sender, "PartyName").text = "My Label"
recipient = ET.SubElement(header, "MessageRecipient")
ET.SubElement(recipient, "PartyId").text = "PADPIDA2020121501Y"
ET.SubElement(recipient, "PartyName").text = "YouTube"
# Resource list
resource_list = ET.SubElement(root, "ResourceList")
sound_recording = ET.SubElement(resource_list, "SoundRecording")
ET.SubElement(sound_recording, "ResourceReference").text = "A1"
details = ET.SubElement(sound_recording, "SoundRecordingDetailsByTerritory")
title = ET.SubElement(details, "Title")
ET.SubElement(title, "TitleText").text = "My Song Title"
ET.SubElement(details, "Duration").text = "PT3M45S"
# Write to file
tree = ET.ElementTree(root)
ET.indent(tree, space=" ")
tree.write("release.xml", xml_declaration=True, encoding="UTF-8")
print("DDEX ERN file generated: release.xml")
A real-world DDEX file includes artist details, ISRC codes, and deal terms. Here's a more complete version:
import xml.etree.ElementTree as ET
from datetime import datetime
def create_ern_release(track_data: dict, sender: dict, recipient: dict) -> ET.Element:
"""Generate a DDEX ERN 4.3 NewReleaseMessage."""
root = ET.Element("ern:NewReleaseMessage", {
"xmlns:ern": "http://ddex.net/xml/ern/43",
"MessageSchemaVersionId": "ern/43",
})
# Header
header = ET.SubElement(root, "MessageHeader")
ET.SubElement(header, "MessageId").text = f"MSG-{datetime.now():%Y%m%d%H%M%S}"
ET.SubElement(header, "MessageCreatedDateTime").text = datetime.now().isoformat()
msg_sender = ET.SubElement(header, "MessageSender")
ET.SubElement(msg_sender, "PartyId").text = sender["dpid"]
ET.SubElement(msg_sender, "PartyName").text = sender["name"]
msg_recipient = ET.SubElement(header, "MessageRecipient")
ET.SubElement(msg_recipient, "PartyId").text = recipient["dpid"]
ET.SubElement(msg_recipient, "PartyName").text = recipient["name"]
# Resource list
resource_list = ET.SubElement(root, "ResourceList")
recording = ET.SubElement(resource_list, "SoundRecording")
ET.SubElement(recording, "ResourceReference").text = "A1"
sr_id = ET.SubElement(recording, "SoundRecordingId")
ET.SubElement(sr_id, "ISRC").text = track_data["isrc"]
details = ET.SubElement(recording, "SoundRecordingDetailsByTerritory")
title_el = ET.SubElement(details, "Title")
ET.SubElement(title_el, "TitleText").text = track_data["title"]
ET.SubElement(details, "Duration").text = track_data["duration"]
# Artists
for artist in track_data.get("artists", []):
contributor = ET.SubElement(details, "DisplayArtist")
name_el = ET.SubElement(contributor, "PartyName")
ET.SubElement(name_el, "FullName").text = artist["name"]
ET.SubElement(contributor, "ArtistRole").text = artist.get("role", "MainArtist")
# Release list
release_list = ET.SubElement(root, "ReleaseList")
release = ET.SubElement(release_list, "Release")
release_id = ET.SubElement(release, "ReleaseId")
ET.SubElement(release_id, "ICPN").text = track_data.get("upc", "")
release_detail = ET.SubElement(release, "ReleaseDetailsByTerritory")
ET.SubElement(release_detail, "TerritoryCode").text = "Worldwide"
# Deal list
deal_list = ET.SubElement(root, "DealList")
deal = ET.SubElement(deal_list, "ReleaseDeal")
deal_terms = ET.SubElement(deal, "Deal")
ET.SubElement(deal_terms, "CommercialModelType").text = "SubscriptionModel"
ET.SubElement(deal_terms, "Usage").text = "OnDemandStream"
validity = ET.SubElement(deal_terms, "ValidityPeriod")
ET.SubElement(validity, "StartDate").text = track_data.get("release_date", "")
return root
# Usage
track = {
"title": "Ocean Waves",
"isrc": "USRC12345678",
"duration": "PT4M12S",
"upc": "0123456789012",
"release_date": "2024-01-15",
"artists": [
{"name": "Jane Doe", "role": "MainArtist"},
{"name": "John Smith", "role": "FeaturedArtist"},
],
}
ern = create_ern_release(
track_data=track,
sender={"dpid": "PADPIDA2023010101A", "name": "My Label"},
recipient={"dpid": "PADPIDA2020121501Y", "name": "YouTube"},
)
tree = ET.ElementTree(ern)
ET.indent(tree, space=" ")
tree.write("release_complete.xml", xml_declaration=True, encoding="UTF-8")
print("Complete DDEX ERN file generated.")
DDEX standards are widely adopted because they solve real problems: interoperability between systems, automated workflows that reduce manual errors, and consistent data formats that ensure artists and rights holders get paid accurately. Most major digital music platforms require DDEX compliance for content delivery.
Have a similar project in mind? We'd love to hear about it.
Get in touch to discuss how we can help bring your vision to life.
Hybrid Database Model in Django for Speed
How combining relational and non-relational databases in Django solved performance bottlenecks for a high-traffic e-commerce catalog microservice.
Maintaining Music Tech Tools: The SLA Dilemma for Small Teams
What happens when a custom streaming analytics tool works perfectly, until nobody is responsible for keeping it running. A real story from the music industry.
Get music tech insights, case studies, and industry news delivered to your inbox.