Release lifecycle
A release is always in one of four states. The state decides who can see it and what happens next.
The states#
| State | How it gets there | Seen by |
|---|---|---|
draft | Created through the API with createRelease | draftRelease, draftReleases — catalog_write only |
pending | Delivered, but not ready to go live | blockedReleases |
active | Published, or delivered complete | releases, release |
withdrawn | Purged by the label, or taken down with withdrawRelease | releases, release |
A release never returns to draft. Publishing a draft makes it active
directly. Delivered releases never pass through draft at all — a DDEX
message is already an assertion by the label. The one way back is out of
withdrawn: reinstateRelease returns a
release to the state it was withdrawn from.
Drafts: authored, not yet asserted#
A draft is work in progress. It can have no UPC, no tracks, no title. It is
visible only to credentials that can author (catalog_write), because
a read-only integration powering someone's app has no business showing a
release nobody has published.
publishRelease is the moment of assertion. It
checks the release is complete — an identifier, at least one resource, bytes
behind every resource, a front cover — and if so makes it active. If not, it
tells you everything that is missing, and the draft stays a draft.
Publishing is recorded as a source: who asserted the release, and when. The person who publishes is the one making the claim, which is why it is the publisher, not whoever started the draft, that is recorded.
Pending: delivered, but held#
A delivered release is held back as pending when it is not ready:
- some files it references have not arrived, or
- it has no front cover with bytes behind it, or
- your catalog is set to hold complete deliveries for review.
Nothing should reach a listener missing its audio or its artwork, so pending
releases are not in releases. They are not hidden, though:
blockedReleases lists every one with the reasons,
because a stuck delivery is something someone needs to chase.
Promotion is automatic. When the missing files land — by redelivery, over
SFTP, or with deliverFile — the release goes
active without anyone pressing anything. See
Out-of-order delivery.
A pending release that will never be completed can be thrown away with discardBlockedRelease. Only pending releases can be discarded: they were never visible, so nothing is taken back.
Active: in the catalog#
An active release is what your applications read. availableFrom records
when it became available in your catalog. That is your catalog's own gate,
and distinct from the label's commercial windows in deals, which say when a
given commercial model may sell it.
Withdrawn: taken down from this catalog#
A label takes a release down by sending a DDEX PurgeReleaseMessage, over
SFTP or through deliverMessage. The release it
names becomes withdrawn in your catalog only — another catalog holding
the same UPC is untouched. A takedown that reaches you some other way, such as
an email or a rights dispute, is withdrawRelease.
Either way, withdrawal is a state, not a delete:
- The release stays listed by releases with
state: "withdrawn"and awithdrawnAt, so your applications can see the takedown and act on it. - Its tracks, artwork and files stay. Media URLs are not refused; what you do with a withdrawn release's files is a matter for your agreement with the label.
- A
pendingrelease can be withdrawn too, and then does not go live when its files arrive.
A purge never creates a release and never changes metadata. A purge naming a release you do not hold does nothing, and one sent over SFTP cannot withdraw a release a different delivery account delivered — two distributors delivering into one catalog cannot take down each other's releases.
Redelivering a withdrawn release updates its metadata but leaves it
withdrawn: a takedown stays until someone undoes it with
reinstateRelease, which returns it to active,
or to pending if it was still waiting for files.
Being told when a release changes state#
A webhook subscribed to
release.state_changed hears about every transition into pending, active
or withdrawn — a delivered release arrives as from: null, a published draft
as from: "draft", a takedown as to: "withdrawn" and a reinstatement as
from: "withdrawn". Drafts themselves are never announced.
release.available is the one to act on: it fires when a release is active
and its availableFrom has come. For a release that goes live with a date
in the future, that is the date, not the moment it went live, so a receiver
that waits for release.available never acts early. See
Webhook events.
Editing after publication#
Published and delivered releases can still be corrected with
updateRelease. When you edit a release a label
delivered, locallyModifiedAt records that it no longer matches what was
sent.
That matters because deliveries win: if the label redelivers, their version
replaces yours. locallyModifiedAt is how you find the releases where that
would undo a correction — and a prompt to send the fix upstream.