# Play Sessions | AudioDN Docs

> API endpoints for creating secure audio playback sessions. Control access to tracks, collections, and playlists with time-limited, scoped play sessions.

Source: https://audiodeliverynetwork.com/docs/api/play-sessions/

---

# Play Sessions

Play sessions manage audio playback for collections, tracks, or playlists.

Each track's resolved `player_color` is accompanied by two read-only companions: `player_color_light` (adjusted to stay legible on a light background) and `player_color_dark` (adjusted for a dark background), so your player can pick the right one for its theme.

POST `/v1/play_session/:scope`

Creates a new play session for a collection or track.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `scope` | string | Required | "collection" or "track" (path parameter). "playlist" is reserved for a future release and currently returns 400. |
| `variants` | array of strings | Optional | Variant settings for the play session |
| `collection_id` | uuid | Optional | ID of the collection (required if scope is 'collection') |
| `track_id` | uuid | Optional | ID of the track (required if scope is 'track') |
| `is_downloadable` | boolean | Optional | Requests that tracks in this session be downloadable. This is only honored when the API key also allows downloads (set per key in the dashboard). The stored session value is api\_key.is\_downloadable AND this request, so a key that forbids downloads always wins — the download endpoint will return 403. |
| `expires_in` | number | Optional | Session duration in seconds (default: 3600, min: 60, max: 86400) |

#### Example Request

    

```
curl -X POST "https://api.audiodelivery.net/v1/play_session/collection" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"collection_id": "COLLECTION_ID", "variants": ["hq", "lq"], "expires_in": 3600}'
```

```
const response = await fetch('https://api.audiodelivery.net/v1/play_session/collection', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({"collection_id": "COLLECTION_ID", "variants": ["hq", "lq"], "expires_in": 3600})
});

const data = await response.json();
```

```
import Foundation

func performRequest() async throws {
    var request = URLRequest(url: URL(string: "https://api.audiodelivery.net/v1/play_session/collection")!)
    request.httpMethod = "POST"
    request.setValue("Bearer YOUR_API_KEY", forHTTPHeaderField: "Authorization")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    let body = {"collection_id": "COLLECTION_ID", "variants": ["hq", "lq"], "expires_in": 3600}
    request.httpBody = try JSONSerialization.data(withJSONObject: body)
    let (data, _) = try await URLSession.shared.data(for: request)
    let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
    // use json
}
```

```
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

val client = OkHttpClient()

suspend fun performRequest(): String = withContext(Dispatchers.IO) {
    val body = """{"collection_id": "COLLECTION_ID", "variants": ["hq", "lq"], "expires_in": 3600}""".toRequestBody("application/json".toMediaType())
    val request = Request.Builder()
        .url("https://api.audiodelivery.net/v1/play_session/collection")
        .post(body)
        .addHeader("Authorization", "Bearer YOUR_API_KEY")
        .build()
    val response = client.newCall(request).execute()
    response.body?.string() ?: error("Empty response body")
}
```

```
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<Map<String, dynamic>> performRequest() async {
  final response = await http.post(
    Uri.parse('https://api.audiodelivery.net/v1/play_session/collection'),
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: jsonEncode({"collection_id": "COLLECTION_ID", "variants": ["hq", "lq"], "expires_in": 3600}),
  );
  if (response.statusCode < 200 || response.statusCode >= 300) {
    throw Exception('Request failed: ${response.statusCode}');
  }
  return jsonDecode(response.body) as Map<String, dynamic>;
}
```

#### Response

```
{
  "ok": true,
  "play_session_id": "uuid",
  "play_session": {
    "id": "uuid",
    "creator_id": "uuid | null",
    "variants": ["string"],
    "is_downloadable": false,
    "expires_at": "string"
  },
  "tracks": [
    { "id": "uuid", "index": "string", "duration": 0, "order": 0, "player_title": "string | null", "player_subtitle": "string | null", "player_color": "string | null", "player_color_light": "string | null", "player_color_dark": "string | null" }
  ],
  "first_track": {
    "track_id": "uuid",
    "cover_image": {
      "icon": { "type": "icon", "width": 80, "height": 80, "url": "string" },
      "small": { "type": "small", "width": 200, "height": 200, "url": "string" },
      "regular": { "type": "regular", "width": 400, "height": 400, "url": "string" }
    },
    "track": {
      "id": "uuid",
      "index": "string",
      "duration": 0,
      "player_title": "string | null",
      "player_subtitle": "string | null",
      "player_color": "string | null",
      "player_color_light": "string | null",
      "player_color_dark": "string | null",
      "theme": [],
      "file_name": "string",
      "info": {},
      "organization_index": "string | null",
      "order": 0,
      "metadata": {},
      "is_dark": false
    },
    "levels": { "levels": [ 0, 0.5, 1 ] },
    "variants": [
      { "path": "string", "url": "string", "variant": { "index": "string" } }
    ]
  },
  "expires_at": "string"
}
```

The `first_track` field includes the first track's full playback data (signed streaming URLs, waveform levels, cover image, and variants) so your player can render immediately without a second API call. Use `GET /v1/play/:session_id/:track_id` to fetch additional tracks on demand.

GET `/v1/play_session/:play_session_id`

Retrieves details about a play session

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `play_session_id` | uuid | Required | The ID of the play session (path parameter) |

#### Example Request

    

```
curl -X GET "https://api.audiodelivery.net/v1/play_session/SESSION_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```
const response = await fetch('https://api.audiodelivery.net/v1/play_session/SESSION_ID', {
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
```

```
import Foundation

func performRequest() async throws {
    var request = URLRequest(url: URL(string: "https://api.audiodelivery.net/v1/play_session/SESSION_ID")!)
    request.setValue("Bearer YOUR_API_KEY", forHTTPHeaderField: "Authorization")
    let (data, _) = try await URLSession.shared.data(for: request)
    let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
    // use json
}
```

```
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.*

val client = OkHttpClient()

suspend fun performRequest(): String = withContext(Dispatchers.IO) {
    val request = Request.Builder()
        .url("https://api.audiodelivery.net/v1/play_session/SESSION_ID")
        .addHeader("Authorization", "Bearer YOUR_API_KEY")
        .build()
    val response = client.newCall(request).execute()
    response.body?.string() ?: error("Empty response body")
}
```

```
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<Map<String, dynamic>> performRequest() async {
  final response = await http.get(
    Uri.parse('https://api.audiodelivery.net/v1/play_session/SESSION_ID'),
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
    },
  );
  if (response.statusCode < 200 || response.statusCode >= 300) {
    throw Exception('Request failed: ${response.statusCode}');
  }
  return jsonDecode(response.body) as Map<String, dynamic>;
}
```

#### Response

```
{
  "ok": true,
  "play_session_id": "uuid",
  "play_session": {
    "id": "uuid",
    "creator_id": "uuid | null",
    "variants": ["string"],
    "is_downloadable": false,
    "expires_at": "string"
  },
  "tracks": [
    { "id": "uuid", "index": "string", "duration": 0, "order": 0, "player_title": "string | null", "player_subtitle": "string | null", "player_color": "string | null", "player_color_light": "string | null", "player_color_dark": "string | null" }
  ],
  "first_track": {
    "track_id": "uuid",
    "cover_image": { "icon": {}, "small": {}, "regular": {} },
    "track": { "id": "uuid", "index": "string", "duration": 0, "player_title": "string | null", "player_subtitle": "string | null", "player_color": "string | null", "player_color_light": "string | null", "player_color_dark": "string | null", "theme": [], "file_name": "string", "info": {}, "organization_index": "string | null", "order": 0, "metadata": {}, "is_dark": false },
    "levels": { "levels": [] },
    "variants": [ { "path": "string", "url": "string", "variant": { "index": "string" } } ]
  }
}
```

The `first_track` field includes the first track's full playback data so your player can render immediately without a second API call.

GET `/v1/play/:play_session_id/:play_track_id`

Retrieves details about a specific track within a play session. No authentication required - the session ID acts as a bearer token.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `play_session_id` | uuid | Required | The ID of the play session (path parameter) |
| `play_track_id` | uuid | Required | The ID of the track within the session (path parameter) |

#### Response

```
{
  "ok": true,
  "play_session_id": "uuid",
  "track_id": "uuid",
  "play_session": {
    "id": "uuid",
    "variants": ["string"],
    "is_downloadable": false,
    "expires_at": "string"
  },
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "string" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "string" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "string" }
  },
  "track": {
    "id": "uuid",
    "index": "string",
    "duration": 0,
    "player_title": "string | null",
    "player_subtitle": "string | null",
    "player_color": "string | null",
    "player_color_light": "string | null",
    "player_color_dark": "string | null",
    "theme": [],
    "file_name": "string",
    "info": {},
    "organization_index": "string | null",
    "order": 0,
    "metadata": {},
    "is_dark": false
  },
  "levels": { "levels": [ 0, 0.5, 1 ] },
  "variants": [
    { "path": "string", "url": "string", "variant": { "index": "string" } }
  ]
}
```

GET `/v1/play/:play_session_id/:play_track_id/:variant_index/download`

Downloads a specific variant of a track. Only available when the session's stored is\_downloadable is true (i.e. the API key allows downloads and the session requested them); otherwise returns 403. No authentication required.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `play_session_id` | uuid | Required | The ID of the play session (path parameter) |
| `play_track_id` | uuid | Required | The ID of the track within the session (path parameter) |
| `variant_index` | string | Required | The index/identifier of the variant to download (path parameter) |

#### Response

Returns a short-lived (30s) signed download URL. The response body is JSON (not the audio file); navigate to `download.url` to fetch the file. The URL is served with `Content-Disposition: attachment` so the browser saves the file instead of playing it inline. If the session is not downloadable, the endpoint returns `403` with an error message.

```
{
  "ok": true,
  "play_session_id": "uuid",
  "track_id": "uuid",
  "download": {
    "variant": "string",
    "url": "string"
  }
}
```
