Track Structure
POSThttps://api.audioscape.ai/developer/v1/track/structureEndpoint
Fetch the beat grid and section metadata for a track. Use this to sync animations, lighting, or VFX to the music — drop a particle burst on every downbeat, trigger a camera shake on the Drop, swap shaders between Verse and Chorus.
Roughly 96% of the catalog has beat grid analysis and 91% has section labels. Tracks without analysis return null for beat_grid and empty arrays for sections/phrases.
Headers
| Name | Type | Description |
|---|---|---|
| x-api-key | required | Your API key |
| Content-Type | required | Must be application/json |
Request Body
| Parameter | Type | Description |
|---|---|---|
| asset_id | string required | The Roblox asset ID of the track. Numeric string. |
Response
Returns the flattened beat grid and section structure for the track.label values come from the classifier vocabulary: Intro, Verse, Chorus, Drop, Bridge, Climax, Outro, Main, Break, Build, Breakdown, Transition, Peak.energy is an integer 1–4.
{
"asset_id": "string",
"duration": number, // seconds
"bpm": number, // tempo, may be null
"track_energy": number, // 0-4 average, may be null
"beat_grid": {
"times": [number], // every beat in seconds
"downbeats": [number] // subset where beat 1 lands
} | null,
"sections": [
{
"start": number,
"end": number,
"label": "Intro" | "Verse" | "Drop" | ...,
"energy": 1 | 2 | 3 | 4 | null,
"bar_start": number,
"bar_end": number,
"bars": null,
"color": "rgba(...)"
}
],
"phrases": [ /* same shape, finer-grained, includes `bars` */ ]
}Example: Sync VFX to downbeats
Using the SDK helpers — fetch the structure once, then drive a particle burst on every downbeat:
local AudioScape = require(ServerScriptService.AudioScape)
local client = AudioScape.new("your-api-key")
local structure, err = client:getStructure({ asset_id = "1843209165" })
if not structure then return end
-- Schedule a burst at every downbeat
for _, t in ipairs(structure.beat_grid.downbeats) do
task.delay(t, function() emitter:Emit(20) end)
end
-- Or query at runtime
local section = client:sectionAtTime("1843209165", currentTime)
if section and section.label == "Drop" then
camera:Shake(section.energy)
endError Responses
400Bad RequestMissing or non-numeric asset_id.
{
"error": "asset_id is required and must be a numeric string"
}404Not FoundThe asset_id doesn't exist in our catalog.
{
"error": "asset_id not found"
}429Too Many RequestsYou've exceeded your rate limit. See your current tier on the API Keys page.
Ready to sync your game to the music?
Grab the SDK and start triggering effects on every beat.
Get Your API Key