//SCHEMADocs
Console
How-to guides

Stream media

Media is never public. Every file has encodings — AAC for streaming, a preview clip, lossless where your plan includes it — and you mint a signed URL for the one you want.

Choose an encoding#

Every audio master you hold is measured and encoded moments after it lands. List what a track has with encodings:

Request
query {
  release(upc: "0196871402293") {
    resources(kind: AUDIO) {
      resourcePk
      title
      encodings {
        encoding
        clip { startMs durationMs }
        original
        codec
        bitrateKbps
        lossless
        sha256
      }
    }
  }
}
Response
{
  "data": {
    "release": {
      "resources": [
        {
          "resourcePk": 771201,
          "title": "Signal Fire",
          "encodings": [
            {
              "encoding": "original",
              "clip": null,
              "original": true,
              "codec": "pcm_s24le",
              "bitrateKbps": 4608,
              "lossless": true,
              "sha256": "9f2c4e0d1a7b3c58e2f6d9a0b4c7e1f3a5d8c2b6e9f0a3d7c1b5e8f2a4d6c9b0"
            },
            {
              "encoding": "aac-256-v1",
              "clip": null,
              "original": false,
              "codec": "aac",
              "bitrateKbps": 256,
              "lossless": false,
              "sha256": "3e7a1c9f5b2d8e4a0c6f1b3d7e9a2c5f8b0d4e6a1c3f5b7d9e2a4c6f8b1d3e5a"
            },
            {
              "encoding": "aac-128-v1",
              "clip": null,
              "original": false,
              "codec": "aac",
              "bitrateKbps": 128,
              "lossless": false,
              "sha256": "b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6"
            },
            {
              "encoding": "aac-128-v1",
              "clip": { "startMs": 30000, "durationMs": 30000 },
              "original": false,
              "codec": "aac",
              "bitrateKbps": 128,
              "lossless": false,
              "sha256": "c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3"
            }
          ]
        }
      ]
    }
  }
}
EncodingMadeWhat it is for
aac-256for every masterThe default stream.
aac-128for every masterCellular, and auditioning.
aac-128, clip: truefor every masterA 30-second preview.
flacfor every master an organization with lossless media holdsThe lossless pull.
mp3-128, mp3-320, mp3-v0, wav, alacon requestDownload stores, legacy players.
original—The bytes you delivered.

encodingProfiles lists them all — read it rather than hardcoding names. A family (aac-256) follows the newest version; a pinned name (aac-256-v1) never changes.

Get a signed URL#

Name the encoding to url:

Request
query {
  release(upc: "0196871402293") {
    resources(kind: AUDIO) {
      title
      url(encoding: "aac-256", ttlSeconds: 600)
    }
  }
}
Response
{
  "data": {
    "release": {
      "resources": [
        {
          "title": "Signal Fire",
          "url": "https://media.schema.fm/sha256/3e/7a/3e7a1c9f…?X-Amz-Expires=600&X-Amz-Signature=…"
        }
      ]
    }
  }
}

The URL is an ordinary HTTPS link. GET it from your server and pull the file into your own pipeline, then check it against the encoding's sha256. Pass download: true and a browser saves it as Artist - Title.m4a instead of playing it.

Artwork has no encodings: ask for url(encoding: "original") on resources(kind: IMAGE), or for a cover at one of your organization's sizes with artwork(size:) — see Size cover art.

Which key may pull what#

The scope depends on what the file is, not on whether it is the original:

ScopeReaches
media_previewclips, and AAC 128
media_readeverything media_preview does, every other lossy encoding, and artwork
media_losslessFLAC, WAV, ALAC, and a lossless original — organizations with lossless media only: every enterprise organization, and others by arrangement

So a DSP's editorial tool can audition a whole catalog with a media_preview key that cannot pull a master-quality file. Lossless is checked against your organization's plan every time a URL is minted, not when the key was made. A master not yet analyzed counts as lossless.

Every URL minted is logged — which key, which file, when — so a leaked link can be traced. The release does not have to be live: if the file is here, you can pull it, and what you do with an unreleased track is governed by your agreement with the label.

Play a preview in a browser#

A signed URL works in an <audio> element, but keep the API key on your server and hand the browser only the preview:

// Your backend: the browser asks to audition a track, you return a fresh URL.
app.get("/api/preview/:upc/:sequence", async (req, res) => {
  const { data } = await schema(
    `query ($upc: String!) {
       release(upc: $upc) {
         resources(kind: AUDIO) { sequence url(encoding: "aac-128", clip: true) }
       }
     }`,
    { upc: req.params.upc },
  );
  const track = data.release?.resources.find((r) => r.sequence === Number(req.params.sequence));
  if (!track?.url) return res.sendStatus(404);
  res.json({ url: track.url });
});

Full-length playback to listeners — tokens, packaging, DRM — is a separate surface, not a signed URL handed to a page.

Choose a lifetime#

ttlSecondsResult
omitted300 seconds (5 minutes)
1–3600as requested
above 3600capped at 3600 (1 hour)
0error

Short is better: a leaked URL is worthless once it expires. Mint URLs when you are about to fetch, not when you render a page of 200 tracks.

When url is null#

A resource can exist before its file does. While state is incoming, url is null — not an error.

Any other null comes with an error whose extensions.code says why: ENCODING_PENDING (it is being made, usually within a minute of the file landing), ENCODING_NOT_REQUESTED, ENCODING_NOT_AVAILABLE, LOSSLESS_NOT_ENABLED and others — see Encodings and media URLs.

Ask for an encoding made on request#

Request
mutation {
  requestEncoding(resourcePk: 771201, encoding: "mp3-320") {
    encoding
    status
  }
}
Response
{
  "data": {
    "requestEncoding": {
      "encoding": "mp3-320-v1",
      "status": "PENDING"
    }
  }
}

Subscribe to resource.encoded and mint the URL when it arrives; nothing needs to poll. Encodings made on request that nobody fetches for 30 days are removed, and can be requested again.

Download the original DDEX file#

Every delivered message keeps its XML exactly as received. Message.sourceUrl signs a link to it:

Request
query {
  messages(limit: 1) {
    fileName
    status
    sourceUrl
  }
}

Raw deliveries contain commercial terms, so this needs media_read.

Use the file's properties#

technical is measured by //SCHEMA from the file itself, not asserted by the sender: codec, sample rate, bit depth, durationMs, whether it is lossless, and EBU R128 loudness (integratedLufs, truePeakDbtp). Compare durationMs with the delivered durationSeconds to catch a truncated or wrong file. It is null until the file has been analyzed; resource.analyzed says when.