Start Jamming Public API

Public data for bluegrass songs, chord charts, lyrics, learning videos, collections, and user-shared custom songs. No API key needed for the documented read endpoints. Friendly to LLM agents.

GET /api/songs/index?for=agent Browse: lightweight per-song metadata GET /api/songs/<id>/full?for=agent Drill in: full song with chords + lyrics GET /api/songs/catalog?for=agent Bulk: every song in one response GET /api/songs/collections?for=agent Browse curated Songbook collections GET /api/learning/catalog-v2/first-party Browse Grass lessons and jam-alongs /llms-full.txt Full agent guide (Markdown)
LLM agents: read the full guide at /llms-full.txt (Markdown, optimized for you). Always append ?for=agent to every /api/songs/* call — it is required, and agent traffic without it will be refused. Questions about integration: elijah@treeforts.org.

Start Jamming LLM Agent Guide

Start Jamming (https://www.startjamming.com) is the website for Grass, a bluegrass jam companion. Its public data includes a canonical Songbook, chord charts, lyrics, demo videos, learning videos, curated collections, and custom songs that their authors have chosen to share.

This guide documents the supported public read surfaces. Other /api/... routes used by the Grass app may require authentication and are not part of the public agent contract.

Contact

Questions about usage, integration, traffic patterns, or high-volume access:

Elijah Mayfield elijah@treeforts.org

Agent identification

Append for=agent to every /api/songs/* request made by an LLM agent. For example:

https://www.startjamming.com/api/songs/index?for=agent

Known agent clients that omit this parameter receive a 400 response linking back to this guide. The parameter also gives agent responses canonical URLs and removes fields that are not reliable enough for agents to surface.

The public Learn and custom-song endpoints documented below do not currently have an agent-specific response mode, so for=agent is not required there.

Canonical Songbook endpoints

These endpoints require no API key or authentication.

URL Use it for ETag
GET /api/songs/search?for=agent&q=... Ranked lookup by exact or partial title, misspelling, song ID, or lyric fragment. limit may be 1 through 20 and defaults to 8. Yes for normal searches
GET /api/songs/index?for=agent Catalog discovery. Returns no chord sections, but currently includes metadata, lyrics, demo URLs, canonical id, human url, and full-song api_url. Yes
GET /api/songs/<id>/full?for=agent One canonical song with legacy song fields plus a normalized arrangement. Add key=G, key=Bb, and so on to transpose the arrangement. Yes, per song
GET /api/songs/catalog?for=agent Every canonical song in one response. Use only for a deliberate bulk mirror. Yes, catalog-wide
GET /api/songs/collections?for=agent Live curated collection definitions and their ordered song IDs. Yes
GET /api/songs/<id>/data?for=agent Full song data, normalized arrangement, and bundles, which are collection memberships for that song. Yes, catalog-wide
GET /api/songs/<id>/content?for=agent Optional editorial sections: about_section, structure_section, jam_section, and is_jambuster. Returns has_content: false when none exists. No
GET /api/songs/<id>/pdf?for=agent&key=A Printable PDF, optionally transposed with key. This returns application/pdf, not JSON. No
GET /api/songs/<id>/backing-track?for=agent&key=A&tempo=100 Generated MP3 backing track. Optional bass, guitar, and mandolin booleans default to true; tempo must be 60 through 200. No

Legacy routes such as GET /api/songs, GET /api/songs/<id>, and GET /api/songs/title/<title> remain available for older clients but should not be used for new integrations. Their response and caching behavior are less consistent than the endpoints above.

Recommended discovery flow

  1. If the user gives a title or lyric fragment and you do not know the canonical song ID, call GET /api/songs/search?for=agent&q=<user text>.
  2. An exact normalized title returns a top-level song object with "match_type": "title_exact". A partial or fuzzy query returns a results array sorted by descending score.
  3. Use score and match_type as confidence signals. Ask a short clarification question when multiple results are close.
  4. Follow the returned api_url when you need the normalized arrangement or the latest complete representation. Do not reconstruct identifiers when the API has already supplied the URL.
  5. For repeated use, cache /api/songs/index?for=agent with its ETag. Revalidate with If-None-Match; an unchanged resource returns 304.

Identifiers and links

Prefer id, api_url, and url exactly as returned.

Index response

The index is an object keyed by internal song_id. Each value carries the canonical public identifiers and links:

{
  "sitting_on_top_of_the_world": {
    "id": "sitting-on-top-of-the-world",
    "canonical_id": "sitting-on-top-of-the-world",
    "song_id": "sitting_on_top_of_the_world",
    "slug": "sitting-on-top-of-the-world",
    "url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
    "api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
    "title": "Sitting On Top Of The World",
    "key": "G",
    "type": "vocal",
    "has_lyrics": true,
    "demo": ["https://www.youtube.com/watch?v=..."],
    "featured_demo": [],
    "updated_at": "2026-06-05T12:00:00"
  }
}

The index omits chord sections and normalized arrangements, but lyrics and demo arrays may be present. Do not assume it is metadata-only. Fetch the returned api_url before presenting a chord chart.

Search responses

Exact normalized title match:

{
  "query": "Sitting on top of the world",
  "normalized_query": "sitting on top of the world",
  "match_type": "title_exact",
  "score": 1.0,
  "id": "sitting-on-top-of-the-world",
  "canonical_id": "sitting-on-top-of-the-world",
  "song_id": "sitting_on_top_of_the_world",
  "slug": "sitting-on-top-of-the-world",
  "url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
  "api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
  "title": "Sitting On Top Of The World",
  "key": "G",
  "type": "vocal",
  "sections": []
}

Partial or fuzzy match:

{
  "query": "Sitting on top of the world",
  "normalized_query": "sitting on top of the world",
  "results": [
    {
      "id": "sitting-on-top-of-the-world",
      "canonical_id": "sitting-on-top-of-the-world",
      "song_id": "sitting_on_top_of_the_world",
      "slug": "sitting-on-top-of-the-world",
      "title": "Sitting On Top Of The World",
      "url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
      "api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
      "score": 0.94,
      "match_type": "title_contains",
      "matched_text": "Sitting On Top Of The World",
      "key": "G",
      "type": "vocal",
      "has_lyrics": true
    }
  ]
}

A lyric match may also include matching_lyrics_line.

Full song response

A /full response contains both legacy source fields and the preferred normalized arrangement:

{
  "id": "clinch-mountain-backstep",
  "song_id": "clinch_mountain_backstep",
  "title": "Clinch Mountain Backstep",
  "key": "Am",
  "type": "fiddle",
  "artist": "Ralph Stanley",
  "tempo": 120,
  "signature": "4/4",
  "sections": [
    {
      "name": "A",
      "repeats": 2,
      "standard_chords": ["Am / / /"]
    }
  ],
  "lyrics": "Verse 1...\n\n<chorus>Chorus...</chorus>",
  "demo": ["https://www.youtube.com/watch?v=..."],
  "featured_demo": [],
  "arrangement": {
    "song_id": "clinch_mountain_backstep",
    "title": "Clinch Mountain Backstep",
    "original_key": "Am",
    "target_key": "Am",
    "signature": "4/4",
    "default_beats_per_measure": 4,
    "sections": [
      {
        "name": "A",
        "repeats": 2,
        "measures": [
          {
            "index": 0,
            "source": "Am / / /",
            "beats": ["Am", "Am", "Am", "Am"],
            "display": "Am / / /",
            "beat_count": 4,
            "has_rest": false
          }
        ]
      }
    ],
    "backing_track_progression": ["Am / / /", "Am / / /"],
    "unique_chords": ["Am"]
  }
}

Agent-mode responses intentionally omit license. Do not infer licensing from its absence and do not copy that field from non-agent responses.

Other fields:

Normalized arrangement

Prefer arrangement for chord rendering, playback, and transposition. It is the server-side normalized interpretation of older section formats.

To transpose, call the API again with a target key:

/api/songs/clinch-mountain-backstep/full?for=agent&key=G

Only the normalized arrangement is transposed. Legacy top-level key, sections, and standard_chords remain in their source form.

Legacy chord notation

Within standard_chords, each string is one measure and tokens are separated by spaces:

The legacy chords field may use a different representation and may be empty. New integrations should use arrangement.sections[].measures[].

Raw sections is usually an ordered array of {name, repeats, standard_chords} objects. Multi-arrangement songs may use older nested shapes in sections and alternate_sections; this is another reason to prefer arrangement for the default arrangement.

Lyrics convention

lyrics is either one string or an array paired by index with lyrics_alternates. Chorus blocks may be wrapped in <chorus>...</chorus>. Treat those tags as semantic markers, remove them from display text, and label the enclosed block as a chorus when useful.

Preserve verse and chorus spacing. Do not claim that lyric blocks map to specific chord sections unless the data explicitly provides that mapping.

Song collections

GET /api/songs/collections?for=agent returns:

{
  "collections": {
    "fundamental_fiddles": {
      "display": "Fundamental Fiddle Tunes",
      "type": "essential",
      "description": "...",
      "songs": ["song_id_one", "song_id_two"],
      "featured": true,
      "sort_order": 0
    }
  }
}

Collection songs values are internal underscore IDs. Resolve them through the Songbook index and use the returned canonical URLs.

The bundles array on /api/songs/<id>/data is the reverse lookup: each entry describes a collection containing that song. It is not a list of demo videos.

Learning catalog

The Learn catalog is public JSON and requires no authentication:

URL Contents
GET /api/learning/catalog-v2/first-party Songs with both a primary Grass lesson and a primary Grass jam-along.
GET /api/learning/catalog-v2/third-party Songs with no primary lesson or jam-along and at least one active bonus lesson or bonus jam-along.
GET /api/learning/catalog-v2 Legacy compatibility view. New integrations should use the two explicit endpoints above.

Each response has schema_version, channels, topics, videos, and jam_alongs. A jam-along entry can contain lesson_video, jam_video, bonus_lesson_videos, and bonus_jam_videos.

Lesson videos may include instrument, instrument_override, and channel_instrument. Effective instrument already applies a video-specific override before the channel default. Current instrument labels include fiddle, banjo, guitar, mandolin, bass, dobro, harmonica, dance, and voice.

The Learn endpoints use server-side static snapshots that refresh after catalog edits. Each response carries an ETag; revalidate with If-None-Match and accept 304.

Shareable custom songs

GET /api/custom-songs/<id-or-slug>/public returns a user-authored custom song when its owner has made it public or unlisted. Private or missing songs return 404. This endpoint requires no authentication and does not currently return an ETag.

Custom songs are user-generated, not canonical Songbook entries. Preserve the returned creator attribution and do not present them as universal Songbook content. The human page is https://www.startjamming.com/custom-songs/<slug>.

Presentation guidance

Caching and etiquette