# Streaming and publishing

Publishing has two parts that meet at the playback URL. A **streaming locator** publishes a specific asset and decides its playback and protection behaviour through a streaming policy. A **streaming endpoint** provides the hostname that players connect to and does the just-in-time packaging and encryption. You need both: a locator gives you a path, an endpoint gives you a host, and the playback URL is the two combined. See [Streaming locators](/mkio/understanding/core-concepts/locators) and [Streaming endpoints](/mkio/understanding/core-concepts/endpoints) for the product background.

## Create and start a streaming endpoint

An endpoint is created with `PUT` and requires `location` and `properties.scaleUnits`. A `scaleUnits` of `0` provisions a shared Standard endpoint; a value above `0` provisions dedicated Premium capacity.

```bash
curl -X PUT "https://app.mk.io/api/v1/projects/<PROJECT_NAME>/media/streamingEndpoints/default" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "location": "<PROJECT_LOCATION>",
    "properties": {
      "scaleUnits": 0,
      "description": "Default streaming endpoint"
    }
  }'
```

Playback only works while the endpoint is running, so start it and confirm the state:

```bash
curl -X POST "https://app.mk.io/api/v1/projects/<PROJECT_NAME>/media/streamingEndpoints/default/start" \
  -H "Authorization: Bearer <YOUR_TOKEN>"

curl -X GET "https://app.mk.io/api/v1/projects/<PROJECT_NAME>/media/streamingEndpoints/default/state" \
  -H "Authorization: Bearer <YOUR_TOKEN>"
```

The endpoint's `hostName` is the value you combine with locator paths to build playback URLs. To enable a Content Delivery Network (CDN), set `cdnEnabled` to `true`; the response then includes a `cdnBasePath` that goes into the URL after the hostname.

## Publish an asset with a streaming locator

A locator is created with `PUT` and requires `assetName` and `streamingPolicyName`. The example publishes an asset for clear (unprotected) streaming.

```bash
curl -X PUT "https://app.mk.io/api/v1/projects/<PROJECT_NAME>/media/streamingLocators/my-locator" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "assetName": "output-video",
      "streamingPolicyName": "Predefined_ClearStreamingOnly"
    }
  }'
```

The locator is also where playback windowing, filters, and protection meet, through optional fields: `startTime` and `endTime` to bound availability, `filters` to apply [playback filters](/api-guides/how-to/media/playback-filters), `defaultContentKeyPolicyName` for [content protection](/api-guides/how-to/media/content-protection), and `suppressed` to take output offline without deleting the locator.

## Choosing a streaming policy

The `streamingPolicyName` decides what playback the locator allows. Use a predefined policy unless you need behaviour they do not cover.

| Policy                                 | Playback                           |
| :------------------------------------- | :--------------------------------- |
| `Predefined_DownloadOnly`              | Download only, no streaming.       |
| `Predefined_ClearStreamingOnly`        | Streaming, no protection.          |
| `Predefined_DownloadAndClearStreaming` | Download and clear streaming.      |
| `Predefined_ClearKey`                  | Clear Key (AES-128) protection.    |
| `Predefined_MultiDrmCencStreaming`     | PlayReady and Widevine.            |
| `Predefined_MultiDrmStreaming`         | PlayReady, Widevine, and FairPlay. |

List the policies available in a project, including any custom ones, with `GET .../media/streamingPolicies`. The DRM policies require a matching content key policy on the locator; see [Content protection](/api-guides/how-to/media/content-protection).

## Build the playback URL

Ask the locator for its relative paths with `listPaths`:

```bash
curl -X POST "https://app.mk.io/api/v1/projects/<PROJECT_NAME>/media/streamingLocators/my-locator/listPaths" \
  -H "Authorization: Bearer <YOUR_TOKEN>"
```

The response groups paths by protocol and encryption under `streamingPaths`, and lists any `downloadPaths`. A playback URL is the endpoint hostname (plus `cdnBasePath` if CDN is enabled) followed by a path:

```text
https://<hostName><cdnBasePath><path_from_listPaths>
```

The manifest path takes format and encryption options in parentheses. For example, an HLS manifest with Apple sample encryption and two filters applied:

```text
https://<hostName>/<streamingLocatorId>/manifest.ism/manifest(format=m3u8-cmaf,encryption=cbcs-aapl,filter=account-filter;asset-filter)
```

Use `format=m3u8-cmaf` for HLS and `format=mpd-time-cmaf` for DASH. The MK.IO product docs recommend fetching playback URLs dynamically through `listPaths` rather than hard-coding them, so that origins can change without breaking clients.

## What goes wrong

- **Playback returns nothing because the endpoint is stopped.** The endpoint must be in the `Running` state. Start it and confirm before testing.
- **A locator returns `404` or `410`.** Before its `startTime`, a locator returns `404 Not Found`; after its `endTime`, it returns `410 Gone`. A `suppressed` locator also returns `404`. Check the time window if playback is unexpectedly unavailable.
- **A DRM policy without a key policy.** Selecting `Predefined_MultiDrmCencStreaming` or similar without a matching content key policy on the locator produces unplayable, encrypted output. See [Content protection](/api-guides/how-to/media/content-protection).

## What comes next

- [Content protection](/api-guides/how-to/media/content-protection): add DRM and key delivery.
- [Automate a VOD pipeline](/api-guides/how-to/media/vod-pipeline): see publishing in an end-to-end workflow.
