# BTR Music — ERN Certification Checklist

Every rule the validator enforces on inbound ERN packages. **Errors** reject the whole package
(all files are extracted and checked before a single record is written); **warnings** are recorded on the
delivery and never block.

## Package (zip)

| Code | Level | Rule |
|---|---|---|
| PKG.OPEN | error | File must be a valid zip; ≤ 2 GB compressed, ≤ 4 GB unzipped; no `../` paths; entries no larger than declared |
| PKG.EXPIRED | error | Re-run requested after the stored package was cleaned up (30 days); deliver again |
| PKG.NO_XML | error | At least one `.xml` ERN message in the zip |
| PKG.READ | error | XML (≤ 64 MB), audio and cover entries must be readable |
| PKG.MISSING_AUDIO | error | Every SoundRecording `File/URI` must exist in the zip |
| PKG.MISSING_COVER | error | The cover `File/URI` must exist in the zip |
| PKG.AUDIO_HASH | error | Declared `HashSum` (SHA-256 / SHA-1 / MD5) must match the audio file |
| PKG.COVER_HASH | warning | Declared cover hash mismatch (accepted, fix at source) |

## Message

| Code | Level | Rule |
|---|---|---|
| ERN.PARSE | error | Well-formed XML; root `NewReleaseMessage` or `PurgeReleaseMessage` |
| ERN.VERSION | error | ERN 4.3.x only; 4.3.2 is recommended. Older versions are rejected |
| ERN.MESSAGE_ID | error | `MessageHeader/MessageId` present (idempotency key) |
| ERN.MESSAGE_ID_DUP | error | The same `MessageId` appears on more than one message in a single package |
| ERN.DUPLICATE | warning | `MessageId` already processed for this partner → message skipped |
| ERN.XSD | error | Fails validation against the official ERN 4.3.2 XSD/AVS bundle. Structural and business-rule checks run on every delivery; XSD schema enforcement is enabled once the ERN 4.3.2 XSD bundle is installed |
| ERN.SENDER | warning | `MessageSender/PartyId` missing |
| ERN.NO_RELEASE | error | At least one `Release` with SoundRecording resources |
| ERN.PURGE_EMPTY / ERN.PURGE_ID | error | PurgeReleaseMessage needs ≥1 `PurgedRelease` with ICPN or GRid |

## Release

| Code | Level | Rule |
|---|---|---|
| REL.ID | error | `ReleaseId/ICPN` (UPC/EAN) or `GRid` |
| REL.UPC_FORMAT | error | ICPN is 12–14 digits |
| REL.GRID_FORMAT | error | GRid contains unsupported characters or length |
| REL.ID_DUP | error | Same ICPN or GRid appears more than once in one message |
| REL.TITLE | error | `DisplayTitleText` (or `DisplayTitle/TitleText`) |
| REL.ARTIST | error | `DisplayArtistName` |
| REL.COVER | error | `Image` with `Type=FrontCoverImage`, linked from the ResourceGroup |
| REL.COVER_QUALITY | error | JPEG/PNG, square (±2 %), ≥600 px |
| REL.COVER_HASH | error | When a cover `HashSum` is supplied it must use SHA-256 |
| REL.COVER_SIZE | warning | <1400 px (1400×1400+ recommended) |
| REL.NO_TRACKS | error | ResourceGroup references ≥1 SoundRecording |
| REL.PLINE / REL.CLINE | warning | PLine / CLine missing |
| REL.GENRE | error | `Genre/GenreText` is required and must be a current BTR Music genre |
| REL.SUBGENRE_UNSUPPORTED | error | `SubGenre` (optional) is not valid for its genre |

## Deals

| Code | Level | Rule |
|---|---|---|
| DEAL.NONE | error | ≥1 `Deal` per release |
| DEAL.USETYPE | error | A deal grants on-demand streaming (`UseType` `OnDemandStream` or `Stream`). `NonInteractiveStream` alone is **not** sufficient |
| DEAL.TERRITORY | error | `TerritoryCode` present (`Worldwide` or ISO 3166-1 alpha-2 list; `ExcludedTerritoryCode` honoured) |
| DEAL.TERRITORY_FORMAT | error | Each `TerritoryCode`/`ExcludedTerritoryCode` is `Worldwide` or a valid ISO 3166-1 alpha-2 code |
| DEAL.RANGE | error | `EndDate` not before `StartDate` |
| DEAL.START | warning | No `StartDate`; effective immediately |
| DEAL.INACTIVE | warning | All deals ended and release not in catalogue; nothing to do |

## Tracks (SoundRecording)

| Code | Level | Rule |
|---|---|---|
| TRK.ISRC | error | `ResourceId/ISRC` (SoundRecording or SoundRecordingEdition level) |
| TRK.ISRC_FORMAT | error | `CC-XXX-YY-NNNNN` (12 alphanumerics, hyphens optional) |
| TRK.ISRC_DUP | error | ISRC repeated within a release |
| TRK.TITLE / TRK.ARTIST | error | `DisplayTitleText`, `DisplayArtistName` |
| TRK.AUDIO | error | `TechnicalDetails/DeliveryFile/File/URI` |
| TRK.AUDIO_FORMAT | error | `.wav .flac .aif .aiff .mp3 .m4a` |
| TRK.AUDIO_HASH | error | Audio must carry a SHA-256 `HashSum` (missing hash, or a non-SHA-256 algorithm) |
| TRK.DURATION | warning | No `Duration`; measured on approval |
| TRK.REMOVED | warning | ISRC dropped from a redelivered release → taken down |

## Artist mapping

| Code | Level | Rule |
|---|---|---|
| ARTIST.UNMAPPED | warning | Main artist not yet mapped; delivery parks as `needs_artist` until resolved in the portal or via API |

## Takedowns (PurgeReleaseMessage / redelivery)

| Code | Level | Rule |
|---|---|---|
| PURGE.UNKNOWN | warning | `PurgeReleaseMessage` references a release not in your catalogue; ignored |
| PURGE.APPLY | error | A referenced release could not be taken down |

## Sandbox

| Code | Level | Rule |
|---|---|---|
| SANDBOX | warning | Partner is in sandbox; validated and recorded, not published |
