Soundtracking with an LLM
Use the Epidemic Sound Partner API + an LLM to automatically find and adapt music for your videos.
Workflow Overview:
Authenticate → Analyze Video (LLM) → Search Music → Preview → Adapt Length
1. Authentication
The Partner API uses a two-token flow. Your backend obtains a Partner Token (never exposed to clients), then requests a User Token for each end user. The User Token is safe to use in frontend code.
POST /v0/partner-tokenPOST /v0/token
See the full authentication docs for details.
Token Lifecycle
| Token | Where to store | TTL |
|---|---|---|
| Partner Token | Backend only | 1 day |
| User Token | Client / frontend | 7 days |
Example: Get a Partner Token
curl -X POST https://partner-content-api.epidemicsound.com/v0/partner-token \
-H "Content-Type: application/json" \
-d '{
"accessKeyId": "YOUR_KEY_ID",
"accessKeySecret": "YOUR_KEY_SECRET"
}'
Example: Get a User Token
curl -X POST https://partner-content-api.epidemicsound.com/v0/token \
-H "Authorization: Bearer PARTNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "userId": "unique-user-id" }'
Use the User Token in subsequent API calls: Authorization: Bearer USER_TOKEN.
2. Video Analysis with an LLM
Before searching for music, analyze your video to extract mood, tempo, and other attributes. You can use any LLM (Gemini, GPT-4, Claude, etc.) that supports video or image input.
Upload a video (or YouTube URL) to your LLM and instruct it to return a JSON object with music search parameters.
Suggested LLM Response Schema
Instruct your LLM to return JSON with fields that map directly to the search API. Use the following schema with descriptions to guide the LLM:
{
"type": "object",
"properties": {
"term": {
"type": "string",
"description": "Search query for finding music. Supports keyword search and semantic search with natural language descriptions. Can include genres, moods, instruments, or descriptive phrases."
},
"mood": {
"type": "array",
"items": {
"type": "string",
"enum": [
"happy",
"hopeful",
"laid-back",
"dreamy",
"peaceful",
"sentimental",
"epic",
"suspense",
"dark",
"angry",
"romantic",
"playful"
]
},
"description": "Array of mood IDs to filter results."
},
"bpmMin": {
"type": "integer",
"description": "Minimum beats per minute filter."
},
"bpmMax": {
"type": "integer",
"description": "Maximum beats per minute filter."
}
}
}
Example output:
{
"term": "uplifting indie folk with acoustic guitar",
"mood": ["happy", "hopeful"],
"bpmMin": 100,
"bpmMax": 120
}
Some LLMs support the JSON Schema examples keyword in the schema, which is useful for steering the output. If the LLM you use does not support schema examples, you can put example values in your prompt text instead—e.g. an "Example output:" block like the one above, or example phrases in the field descriptions.
The allowed values for mood in the schema should be dynamically fetched from the Partner API (e.g. GET /v0/moods or GET /v0/tracks/parameters) and used to build the enum in your schema, so it stays in sync with the catalog.
3. Search Music
Call the search endpoint with the query generated by your LLM. You can refine results with mood, genre, and BPM filters.
GET /v0/tracks/search
See the search endpoint docs for details.
Example Request
curl "https://partner-content-api.epidemicsound.com/v0/tracks/search?term=uplifting%20indie%20folk&limit=10" \
-H "Authorization: Bearer USER_TOKEN"
Key Query Parameters
| Parameter | Description |
|---|---|
term | Search query — supports keywords (genres, moods, instruments) and semantic search with natural language |
mood | Mood ID(s) — array or comma-separated |
genre | Genre ID(s) — array or comma-separated |
bpmMin / bpmMax | BPM range filter |
limit | Results per page (default 50, max 60) |
offset | Pagination offset |
sort | Relevance, Date, Title |
Response Fields to Display
Each track in the response includes:
id– unique track ID (use with/v0/tracks/{id}/streamfor playback)title– track titlemainArtist– artist namebpm– beats per minutelength– duration in secondsimageUrl– cover art URL
4. Preview Playback
Display search results in a list with cover art, title, artist, BPM, and duration. Add a play/pause button to preview each track.
GET /v0/tracks/{trackId}/stream
See the stream endpoint docs for details.
How Streaming Works
- The stream endpoint returns a manifest URL (HLS format) for adaptive streaming.
- Audio is encoded in AAC format (smaller footprint than MP3 for similar quality).
- To play the manifest URL: use hls.js in web browsers; Safari/iOS have native support; ExoPlayer on Android.
Preview Player Example
<audio id="preview"></audio>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
const audio = document.getElementById('preview')
async function playTrack(trackId, userToken) {
const res = await fetch(
`https://partner-content-api.epidemicsound.com/v0/tracks/${trackId}/stream`,
{ headers: { Authorization: `Bearer ${userToken}` } }
)
const { url: streamUrl } = await res.json()
if (Hls.isSupported()) {
const hls = new Hls()
hls.loadSource(streamUrl)
hls.attachMedia(audio)
hls.on(Hls.Events.MANIFEST_PARSED, () => audio.play())
} else if (audio.canPlayType('application/vnd.apple.mpegurl')) {
audio.src = streamUrl
audio.play()
}
}
</script>
5. Select & Adapt Length
Once the user picks a track, you can generate an edited version that matches their video duration. The Partner API provides Edit Versions endpoints for this (a.k.a. "adapt length").
POST /v0/tracks/{trackId}/versionsGET /v0/tracks/{trackId}/versions/{jobId}
See the edit versions endpoint docs for details.
Flow
- Start a job: POST to
/v0/tracks/{trackId}/versionswith your target duration in milliseconds (1 second to 5 minutes max).
curl -X POST "https://partner-content-api.epidemicsound.com/v0/tracks/123456/versions" \
-H "Authorization: Bearer USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "targetDurationMs": 30000 }'
The response includes a jobId.
- Poll for status: GET
/v0/tracks/{trackId}/versions/{jobId}untilstatusisCOMPLETED.
curl "https://partner-content-api.epidemicsound.com/v0/tracks/123456/versions/JOB_ID" \
-H "Authorization: Bearer USER_TOKEN"
- Use the result: When complete, the response contains preview and download URLs for the adapted track.
Job Status Values
| Status | Meaning |
|---|---|
PENDING | Job queued |
IN_PROGRESS | Processing |
COMPLETED | Ready – URLs available |
FAILED | Error occurred |
Longer durations increase processing time. Poll every 2–5 seconds until complete.