← API Reference

Track Structure

POST
https://api.audioscape.ai/developer/v1/track/structure

Endpoint

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

NameTypeDescription
x-api-keyrequiredYour API key
Content-TyperequiredMust be application/json

Request Body

ParameterTypeDescription
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:

Luau (Roblox)
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)
end

Error Responses

400Bad Request

Missing or non-numeric asset_id.

{
  "error": "asset_id is required and must be a numeric string"
}
404Not Found

The asset_id doesn't exist in our catalog.

{
  "error": "asset_id not found"
}
429Too Many Requests

You'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