Skip to main content

Identifier Types

Complete reference for standard identifiers, codes, and unique keys used throughout DDEX messages.

Overview

DDEX employs various standardized identifier systems to ensure global uniqueness and enable cross-platform content identification. These identifiers serve as the foundation for content tracking, rights management, and commercial operations.

Standard Identifier Categories

Audio Content Identifiers

IdentifierFull NameScopeFormatExample
ISRCInternational Standard Recording CodeSound recordings12 charactersUSRC17607839
ISWCInternational Standard Musical Work CodeMusical worksVariableT-010.015.001-1
GRIDGlobal Release IdentifierReleases18 charactersA1-2425G-ABC1234002-M

Product Identifiers

IdentifierFull NameScopeFormatExample
UPCUniversal Product CodeProducts (North America)12 digits123456789012
EANEuropean Article NumberProducts (International)13 digits1234567890123
GTINGlobal Trade Item NumberProducts (Global)8/12/13/14 digits01234567890128

Party Identifiers

IdentifierFull NameScopeFormatExample
DPIDDDEX Party IdentifierDDEX parties21 charactersPADPIDA2014101001U
ISNIInternational Standard Name IdentifierPeople/organizations16 digits0000 0001 2280 7671
IPIInterested Parties InformationRights holders9-11 digits00052210040

ISRC (International Standard Recording Code)

Format Structure

[Country Code][Registrant][Year][Serial]
2 chars 3 chars 2 digits 5 digits

Components

  • Country Code: ISO 3166-1 alpha-2 (e.g., US, GB, DE)
  • Registrant: Alphanumeric code assigned to registrant
  • Year: Last 2 digits of registration year
  • Serial: Sequential number for recordings

Examples and Validation

interface ISRC {
value: string; // Full ISRC code
countryCode: string; // 2-character country
registrant: string; // 3-character registrant
year: string; // 2-digit year
serial: string; // 5-digit serial
}

// Validation regex
const ISRC_PATTERN = /^[A-Z]{2}[A-Z0-9]{3}\d{7}$/;

// Examples
const validISRCs = [
'USRC17607839', // US registrant RC1, year 17, serial 607839
'GBUM71505078', // GB registrant UM7, year 15, serial 05078
'DEAR81000001' // DE registrant AR8, year 10, serial 00001
];

function validateISRC(isrc: string): boolean {
return ISRC_PATTERN.test(isrc);
}

function parseISRC(isrc: string): ISRC | null {
if (!validateISRC(isrc)) return null;

return {
value: isrc,
countryCode: isrc.substring(0, 2),
registrant: isrc.substring(2, 5),
year: isrc.substring(5, 7),
serial: isrc.substring(7, 12)
};
}

UPC/EAN Product Codes

UPC-A Format (12 digits)

[System][Manufacturer][Product][Check]
1 digit 5 digits 5 digits 1 digit

EAN-13 Format (13 digits)

[Country][Manufacturer][Product][Check]
2-3 digits 4-5 digits 3-5 digits 1 digit

Validation and Calculation

interface ProductCode {
value: string;
type: 'UPC' | 'EAN';
isValid: boolean;
checkDigit: number;
}

function calculateUPCCheckDigit(code: string): number {
const digits = code.substring(0, 11).split('').map(Number);
const sum = digits.reduce((acc, digit, index) => {
return acc + digit * (index % 2 === 0 ? 1 : 3);
}, 0);
return (10 - (sum % 10)) % 10;
}

function calculateEANCheckDigit(code: string): number {
const digits = code.substring(0, 12).split('').map(Number);
const sum = digits.reduce((acc, digit, index) => {
return acc + digit * (index % 2 === 0 ? 1 : 3);
}, 0);
return (10 - (sum % 10)) % 10;
}

function validateProductCode(code: string): ProductCode {
const cleanCode = code.replace(/\D/g, '');

if (cleanCode.length === 12) {
const checkDigit = calculateUPCCheckDigit(cleanCode);
const providedCheck = parseInt(cleanCode.charAt(11));

return {
value: cleanCode,
type: 'UPC',
isValid: checkDigit === providedCheck,
checkDigit
};
} else if (cleanCode.length === 13) {
const checkDigit = calculateEANCheckDigit(cleanCode);
const providedCheck = parseInt(cleanCode.charAt(12));

return {
value: cleanCode,
type: 'EAN',
isValid: checkDigit === providedCheck,
checkDigit
};
}

return {
value: cleanCode,
type: cleanCode.length === 12 ? 'UPC' : 'EAN',
isValid: false,
checkDigit: -1
};
}

DPID (DDEX Party Identifier)

Format Structure

[Prefix][Country][Type][Date][Sequence][Check]
P AD P IDA 2014 10 10 01 U

Components

  • Prefix: Always "P"
  • Authority: "AD" for DDEX
  • Type: "P" for Party, "S" for Service
  • Prefix Code: "IDA"
  • Registration Date: YYYYMMDD
  • Sequence: Sequential number
  • Check Character: Calculated check

DPID Examples

interface DPID {
value: string;
authority: string;
type: 'Party' | 'Service';
registrationDate: Date;
sequence: string;
checkCharacter: string;
}

// Examples
const validDPIDs = [
'PADPIDA2014101001U', // Party registered 2014-10-10, sequence 01
'PADPIDA2015032515G', // Party registered 2015-03-25, sequence 15
'PADSIDA2016081203M' // Service registered 2016-08-12, sequence 03
];

function parseDPID(dpid: string): DPID | null {
const pattern = /^P(AD)(P|S)(IDA)(\d{8})(\d{2})([A-Z])$/;
const match = dpid.match(pattern);

if (!match) return null;

const [, authority, type, prefix, dateStr, sequence, check] = match;
const year = parseInt(dateStr.substring(0, 4));
const month = parseInt(dateStr.substring(4, 6)) - 1;
const day = parseInt(dateStr.substring(6, 8));

return {
value: dpid,
authority,
type: type === 'P' ? 'Party' : 'Service',
registrationDate: new Date(year, month, day),
sequence,
checkCharacter: check
};
}

ISNI (International Standard Name Identifier)

Format and Structure

[Block 1][Block 2][Block 3][Block 4]
4 digits 4 digits 4 digits 4 digits (with check digit)

ISNI Validation

interface ISNI {
value: string; // Full ISNI
formatted: string; // With spaces: "0000 0001 2280 7671"
checkDigit: string; // Last character (digit or X)
isValid: boolean;
}

function validateISNI(isni: string): ISNI {
// Remove spaces and normalize
const cleaned = isni.replace(/\s/g, '');
const digits = cleaned.substring(0, 15);
const providedCheck = cleaned.charAt(15);

// Calculate check digit
let total = 0;
for (let i = 0; i < 15; i++) {
total = (total + parseInt(digits.charAt(i))) * 2;
}

const remainder = total % 11;
const calculatedCheck = remainder === 1 ? 'X' : ((12 - remainder) % 11).toString();

return {
value: cleaned,
formatted: cleaned.replace(/(\d{4})(\d{4})(\d{4})(\d{4})/, '$1 $2 $3 $4'),
checkDigit: calculatedCheck,
isValid: providedCheck === calculatedCheck
};
}

// Examples
const validISNIs = [
'0000000123456789', // Numeric check digit
'000000012345678X', // X check digit for remainder 1
'0000 0001 2280 7671' // Formatted with spaces
];

GRid (Global Release Identifier)

Format Structure

[Scheme][Issuer][Release][Check]
A1 2425G ABC1234002 M

Components

  • Scheme: "A1" for current scheme
  • Issuer: 5-character issuer code
  • Release: 10-character release identifier
  • Check: Single check character

GRid Examples

interface GRid {
value: string;
scheme: string;
issuer: string;
release: string;
checkCharacter: string;
}

function parseGRid(grid: string): GRid | null {
// Remove hyphens if present
const cleaned = grid.replace(/-/g, '');

if (cleaned.length !== 18) return null;

return {
value: cleaned,
scheme: cleaned.substring(0, 2),
issuer: cleaned.substring(2, 7),
release: cleaned.substring(7, 17),
checkCharacter: cleaned.substring(17, 18)
};
}

// Format with standard hyphens
function formatGRid(grid: string): string {
const cleaned = grid.replace(/-/g, '');
return `${cleaned.substring(0, 2)}-${cleaned.substring(2, 7)}-${cleaned.substring(7, 17)}-${cleaned.substring(17, 18)}`;
}

// Examples
const validGRids = [
'A1-2425G-ABC1234002-M',
'A1-LABEL-REL0000001-7',
'A1-DIST1-XYZ9876543-K'
];

Proprietary Identifiers

Namespace System

interface ProprietaryId {
namespace: string; // Organization identifier
value: string; // Value within namespace
schemeURI?: string; // Optional scheme URI
}

// Common proprietary namespace examples
const proprietaryExamples = [
{
namespace: 'Spotify',
value: 'spotify:track:4iV5W9uYEdYUVa79Axb7Rh',
schemeURI: 'https://open.spotify.com'
},
{
namespace: 'AppleMusic',
value: '1234567890',
schemeURI: 'https://music.apple.com'
},
{
namespace: 'YouTubeMusic',
value: 'MPLAyb_mkp1c',
schemeURI: 'https://music.youtube.com'
},
{
namespace: 'InternalLabel',
value: 'LABEL-2024-001-TRACK-05'
}
];

Identifier Mapping and Resolution

Cross-Platform Mapping

interface IdentifierMapping {
primaryId: string; // Primary identifier (usually ISRC)
platformMappings: Map<string, string>;
lastUpdated: Date;
confidence: number; // 0-1 confidence score
}

class IdentifierResolver {
private mappings = new Map<string, IdentifierMapping>();

addMapping(primaryId: string, platform: string, platformId: string): void {
let mapping = this.mappings.get(primaryId);
if (!mapping) {
mapping = {
primaryId,
platformMappings: new Map(),
lastUpdated: new Date(),
confidence: 1.0
};
this.mappings.set(primaryId, mapping);
}

mapping.platformMappings.set(platform, platformId);
mapping.lastUpdated = new Date();
}

resolveToISRC(platformId: string, platform: string): string | null {
for (const [isrc, mapping] of this.mappings) {
if (mapping.platformMappings.get(platform) === platformId) {
return isrc;
}
}
return null;
}

resolveToPlatform(isrc: string, platform: string): string | null {
const mapping = this.mappings.get(isrc);
return mapping?.platformMappings.get(platform) || null;
}
}

Identifier Generation

ISRC Generation

class ISRCGenerator {
private countryCode: string;
private registrant: string;
private currentYear: number;
private serialCounter: number = 1;

constructor(countryCode: string, registrant: string) {
this.countryCode = countryCode.toUpperCase();
this.registrant = registrant.toUpperCase();
this.currentYear = new Date().getFullYear();
}

generateISRC(): string {
const year = (this.currentYear % 100).toString().padStart(2, '0');
const serial = this.serialCounter.toString().padStart(5, '0');
this.serialCounter++;

return `${this.countryCode}${this.registrant}${year}${serial}`;
}

generateBatch(count: number): string[] {
return Array.from({ length: count }, () => this.generateISRC());
}
}

// Usage
const generator = new ISRCGenerator('US', 'RC1');
const newISRCs = generator.generateBatch(10);
// ['USRC24000001', 'USRC24000002', ...]

UPC Generation

class UPCGenerator {
private manufacturerPrefix: string;
private productCounter: number = 1;

constructor(manufacturerPrefix: string) {
if (manufacturerPrefix.length !== 6) {
throw new Error('Manufacturer prefix must be 6 digits');
}
this.manufacturerPrefix = manufacturerPrefix;
}

generateUPC(): string {
const productCode = this.productCounter.toString().padStart(5, '0');
this.productCounter++;

const partial = `0${this.manufacturerPrefix}${productCode}`;
const checkDigit = calculateUPCCheckDigit(partial);

return `${partial}${checkDigit}`;
}
}

// Usage
const upcGen = new UPCGenerator('123456');
const newUPC = upcGen.generateUPC(); // '012345600001X'

Validation Integration

Multi-Identifier Validation

interface ValidationResult {
identifier: string;
type: string;
isValid: boolean;
errors: string[];
warnings: string[];
}

class IdentifierValidator {
validateAll(identifiers: Record<string, string>): ValidationResult[] {
const results: ValidationResult[] = [];

for (const [type, value] of Object.entries(identifiers)) {
switch (type.toLowerCase()) {
case 'isrc':
results.push(this.validateISRC(value));
break;
case 'upc':
case 'ean':
results.push(this.validateProductCode(value));
break;
case 'dpid':
results.push(this.validateDPID(value));
break;
case 'isni':
results.push(this.validateISNI(value));
break;
case 'grid':
results.push(this.validateGRid(value));
break;
default:
results.push({
identifier: value,
type,
isValid: true, // Assume proprietary IDs are valid
errors: [],
warnings: [`Unknown identifier type: ${type}`]
});
}
}

return results;
}

private validateISRC(isrc: string): ValidationResult {
const isValid = validateISRC(isrc);
return {
identifier: isrc,
type: 'ISRC',
isValid,
errors: isValid ? [] : ['Invalid ISRC format'],
warnings: []
};
}

// Additional validation methods...
}

Best Practices

Identifier Management

  1. Consistency: Use consistent identifier formats across all systems
  2. Validation: Always validate identifiers before storing or transmitting
  3. Normalization: Store identifiers in normalized format (uppercase, no spaces)
  4. Mapping: Maintain cross-platform identifier mappings
  5. Generation: Use proper generation algorithms for new identifiers

Data Quality

  1. Verification: Cross-reference identifiers with authoritative sources
  2. Deduplication: Detect and resolve duplicate identifier assignments
  3. Monitoring: Monitor for identifier format changes or new standards
  4. Backup Systems: Maintain fallback identification methods
  5. Documentation: Document custom identifier schemes thoroughly

Performance Optimization

  1. Indexing: Index identifier fields for fast lookups
  2. Caching: Cache frequently accessed identifier mappings
  3. Batch Processing: Process identifier operations in batches
  4. Normalization: Pre-normalize identifiers during ingestion
  5. Validation: Use efficient validation algorithms for high-volume operations