Mobile Integration
Use ADN's API with Client-Side API Keys from your iOS, Android, or Flutter app. Play and upload with native media elements.
Best For
Playing Tracks
Create play sessions and stream audio with native media players.
Call ADN's playback API directly from your mobile app using a Client-Side API Key. Create play sessions, fetch signed variant URLs, and stream audio with native media players.
1. Create a Client-Side Player API Key
Under Settings → API Keys, create a Client-Side Player key. Scope it to the variants and content your mobile app should access.
2. Create a Play Session
import Foundation
struct PlaySessionRequest: Encodable {
let collectionId: String
let variants: [String]
let isDownloadable: Bool
let expiresIn: Int
enum CodingKeys: String, CodingKey {
case collectionId = "collection_id"; case variants
case isDownloadable = "is_downloadable"; case expiresIn = "expires_in"
}
}
struct PlaySessionResponse: Decodable {
let playSessionId: String
let tracks: [Track]
enum CodingKeys: String, CodingKey { case playSessionId = "play_session_id"; case tracks }
struct Track: Decodable { let id: String }
}
func createPlaySession() async throws -> (playSessionId: String, tracks: [PlaySessionResponse.Track]) {
var request = URLRequest(url: URL(string: "https://api.audiodelivery.net/v1/play_session/collection")!)
request.httpMethod = "POST"
request.setValue("Bearer CLIENT-SIDE-PLAYER-API-KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
request.httpBody = try encoder.encode(PlaySessionRequest(
collectionId: "COLLECTION-ID", variants: ["hq", "lq"], isDownloadable: false, expiresIn: 3600))
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let session = try decoder.decode(PlaySessionResponse.self, from: data)
return (session.playSessionId, session.tracks)
} 3. Fetch Track Variant URLs
struct TrackVariantsResponse: Decodable {
let variants: [Variant]
struct Variant: Decodable {
let url: String
let variant: VariantIndex
struct VariantIndex: Decodable { let id: String }
}
}
// No auth needed — the session ID acts as a bearer token
func getAudioUrl(playSessionId: String, trackId: String) async throws -> String {
let url = URL(string: "https://api.audiodelivery.net/v1/play/\(playSessionId)/\(trackId)")!
let (data, _) = try await URLSession.shared.data(from: url)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let res = try decoder.decode(TrackVariantsResponse.self, from: data)
let hq = res.variants.first { $0.variant.id == "hq" }!
return hq.url
} 4. Play with Native Player
import AVFoundation
let player = AVPlayer(url: URL(string: audioUrl)!)
player.play() The signed URL works with any native media player. ADN handles CDN delivery and URL verification.
Waveform Data
levels field in the track response contains the data — use it to render waveforms
in your own player, or generate custom waveforms via the Audio Analysis variant type.
Cover Images & Theme Colors
cover_image
in the track response (in icon/small/regular/large sizes). You can also upload a cover image
separately via the API. When a cover image is present, ADN extracts a palette of colors
and selects a primary player_color — use these to style your player UI. The full
image_colors array contains all extracted colors with hex values, area, lightness, and saturation data.
Uploading Tracks
Upload audio files from native apps using ADN's upload API.
Call ADN's upload API directly from your mobile app using a Client-Side API Key. Create upload sessions, get presigned URLs, and upload audio files — all from native code.
1. Create a Client-Side Upload API Key
Login to ADN, go to Settings → API Keys, and create a Client-Side Upload key. Scope it to the collection your app should upload to.
2. Create an Upload Session
import Foundation
struct UploadSessionRequest: Encodable {
let collectionId: String
let expiresIn: Int
enum CodingKeys: String, CodingKey { case collectionId = "collection_id"; case expiresIn = "expires_in" }
}
struct UploadSessionResponse: Decodable {
let uploadSession: UploadSession
enum CodingKeys: String, CodingKey { case uploadSession = "upload_session" }
struct UploadSession: Decodable { let id: String }
}
func createUploadSession() async throws -> String {
var request = URLRequest(url: URL(string: "https://api.audiodelivery.net/v1/upload_session")!)
request.httpMethod = "POST"
request.setValue("Bearer CLIENT-SIDE-UPLOAD-API-KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
request.httpBody = try encoder.encode(UploadSessionRequest(collectionId: "COLLECTION-ID", expiresIn: 3600))
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let session = try decoder.decode(UploadSessionResponse.self, from: data)
return session.uploadSession.id
} 3. Get a Track Upload URL
struct TrackUploadRequest: Encodable {
let fileName: String
enum CodingKeys: String, CodingKey { case fileName = "file_name" }
}
struct TrackUploadResponse: Decodable {
let trackUpload: TrackUpload
enum CodingKeys: String, CodingKey { case trackUpload = "track_upload" }
struct TrackUpload: Decodable { let uploadUrl: String; let method: String
enum CodingKeys: String, CodingKey { case uploadUrl = "upload_url"; case method }
}
}
func getTrackUploadUrl(sessionId: String) async throws -> (url: String, method: String) {
var request = URLRequest(url: URL(string: "https://api.audiodelivery.net/v1/upload/\(sessionId)/track")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
request.httpBody = try encoder.encode(TrackUploadRequest(fileName: "recording.m4a"))
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let res = try decoder.decode(TrackUploadResponse.self, from: data)
return (res.trackUpload.uploadUrl, res.trackUpload.method)
} 4. Upload the File
// Prefer streaming for large files instead of loading into memory
func uploadAudio(fileURL: URL, uploadURL: URL, method: String) async throws {
var request = URLRequest(url: uploadURL)
request.httpMethod = method
request.setValue("audio/mp4", forHTTPHeaderField: "Content-Type")
request.httpBodyStream = InputStream(url: fileURL)
let (_, uploadResponse) = try await URLSession.shared.data(for: request)
let httpResponse = uploadResponse as! HTTPURLResponse
print("Upload status: \(httpResponse.statusCode)") // 200 on success
} 5. Optional: Webhooks
Add a webhook under Settings → Webhooks to be notified when processing finishes.
Cover Images
image_colors)
that can be used to style your player UI.