Skip to main content

Overview

The Songs API manages your worship song library with support for church-specific and global songs. It includes a collaborative editing workflow where members can propose changes that require approval.

Authentication

All endpoints require authentication with specific permissions:
  • Read: song.read
  • Create: song.create
  • Update: song.update
  • Delete: song.delete
  • Approve Edits: song.approve
Authorization: Bearer YOUR_JWT_TOKEN

List Songs

GET /api/songs

Retrieve all songs in the library
Required Permission: song.read

Query Parameters

church_id
integer
Filter songs by church ID. Super admins can omit this to see all songs.
churchId
integer
Alternative parameter for church_id

Request

# Church-specific songs
curl -X GET "https://your-domain.com/api/songs?church_id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"

# All songs (super admin only)
curl -X GET https://your-domain.com/api/songs \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

success
boolean
Indicates if the request was successful
songs
array
Array of song objects
{
  "success": true,
  "songs": [
    {
      "id": 1,
      "church_id": 1,
      "church_name": "First Baptist Church",
      "title": "Great Are You Lord",
      "artist": "All Sons & Daughters",
      "original_key": "C",
      "tempo": "72 BPM",
      "category": "Worship",
      "content": "[Verse 1]\nYou give life...",
      "created_at": "2024-01-15 10:30:00"
    },
    {
      "id": 2,
      "church_id": 0,
      "church_name": null,
      "title": "10,000 Reasons",
      "artist": "Matt Redman",
      "original_key": "G",
      "tempo": "73 BPM",
      "category": "Praise",
      "content": "[Chorus]\nBless the Lord...",
      "created_at": "2024-01-10 09:15:00"
    }
  ]
}
Note: Songs with church_id: 0 are global songs available to all churches.

Get Song by ID

GET /api/songs/{id}

Retrieve detailed information about a specific song
Required Permission: song.read

Request Parameters

id
integer
required
The unique identifier of the song

Request

curl -X GET https://your-domain.com/api/songs/1 \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "success": true,
  "song": {
    "id": 1,
    "church_id": 1,
    "title": "Great Are You Lord",
    "artist": "All Sons & Daughters",
    "original_key": "C",
    "tempo": "72 BPM",
    "category": "Worship",
    "content": "[Verse 1]\nYou give life, You are love\nYou bring light to the darkness\n\n[Chorus]\nGreat are You Lord...",
    "created_at": "2024-01-15 10:30:00",
    "updated_at": "2024-02-20 14:45:00"
  }
}

Error Response

Not Found (404)
{
  "success": false,
  "error": "Song not found"
}

Create Song

POST /api/songs

Add a new song to the library
Required Permission: song.create

Request Body

title
string
required
The title of the song
artist
string
required
The artist or composer name
church_id
integer
Church ID (0 for global songs, or specific church ID)
original_key
string
The original key of the song (e.g., “C”, “G”, “D”)
tempo
string
The tempo (e.g., “72 BPM”, “Moderate”)
category
string
Song category (e.g., “Worship”, “Praise”, “Prayer”)
content
string
Full lyrics and chords in chord-pro or plain text format

Request

curl -X POST https://your-domain.com/api/songs \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Amazing Grace",
    "artist": "John Newton",
    "church_id": 1,
    "original_key": "G",
    "tempo": "90 BPM",
    "category": "Hymn",
    "content": "[Verse 1]\nAmazing grace how sweet the sound\nThat saved a wretch like me"
  }'

Response

{
  "success": true,
  "id": 15,
  "message": "Song created"
}

Error Responses

Missing Required Fields (400)
{
  "success": false,
  "error": "Title and Artist are required"
}
Creation Failed
{
  "success": false,
  "error": "Failed to create song"
}

Update Song

PUT /api/songs/{id}

Update an existing song
Required Permission: song.update

Request Parameters

id
integer
required
The ID of the song to update
title
string
Updated title
artist
string
Updated artist
original_key
string
Updated key
tempo
string
Updated tempo
category
string
Updated category
content
string
Updated lyrics/chords

Request

curl -X PUT https://your-domain.com/api/songs/1 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Great Are You Lord (Updated)",
    "original_key": "D",
    "tempo": "75 BPM"
  }'

Response

{
  "success": true,
  "message": "Song updated"
}

Propose Edit

POST /api/songs/propose_edit

Propose changes to a song (requires approval)
Note: Members without song.update permission can propose edits that must be approved by someone with song.approve permission.

Request Body

song_id
integer
required
The ID of the song to edit
data
object
required
Object containing the proposed changes

Request

curl -X POST https://your-domain.com/api/songs/propose_edit \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "song_id": 1,
    "data": {
      "title": "Great Are You Lord",
      "content": "[Verse 1]\nUpdated lyrics...",
      "original_key": "D"
    }
  }'

Response

{
  "success": true,
  "message": "Edición propuesta"
}

List Pending Edits

GET /api/songs/edits

Retrieve all pending song edit proposals
Required Permission: song.approve

Request

curl -X GET https://your-domain.com/api/songs/edits \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "success": true,
  "edits": [
    {
      "id": 3,
      "song_id": 1,
      "song_title": "Great Are You Lord",
      "proposed_by_member_id": 12,
      "proposed_by_name": "Emily Davis",
      "proposed_data": {
        "title": "Great Are You Lord",
        "original_key": "D",
        "content": "Updated lyrics..."
      },
      "status": "pending",
      "created_at": "2024-03-15 10:30:00"
    }
  ]
}

Resolve Edit Proposal

POST /api/songs/resolve_edit

Approve or reject a proposed song edit
Required Permission: song.approve

Request Body

id
integer
required
The ID of the edit proposal
status
string
required
Resolution status: “approved” or “rejected”

Request (Approve)

curl -X POST https://your-domain.com/api/songs/resolve_edit \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 3,
    "status": "approved"
  }'

Request (Reject)

curl -X POST https://your-domain.com/api/songs/resolve_edit \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 3,
    "status": "rejected"
  }'

Response

{
  "success": true,
  "message": "Edición aprobada"
}
When approved: The proposed changes are applied to the song.

Delete Song

DELETE /api/songs/{id}

Delete a song from the library
Required Permission: song.delete

Request Parameters

id
integer
required
The ID of the song to delete

Request

curl -X DELETE https://your-domain.com/api/songs/1 \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "success": true,
  "message": "Song deleted"
}

Song Categories

Common category values:
  • Worship - Worship and adoration songs
  • Praise - Celebratory praise songs
  • Prayer - Prayer and meditation songs
  • Hymn - Traditional hymns
  • Contemporary - Modern worship songs
  • Gospel - Gospel music

Global vs Church Songs

church_idVisibilityUse Case
0All churchesStandard worship songs, hymns
1+Specific churchChurch-specific arrangements, original songs

Collaborative Editing Workflow

  1. Member proposes edit → Creates pending edit record
  2. Approver reviews → Views pending edits via /api/songs/edits
  3. Approver resolves → Approves or rejects via /api/songs/resolve_edit
  4. If approved → Changes are applied to the song
  5. Activity logged → Tracks who approved/rejected

Error Codes

CodeDescription
400Bad Request - Missing required fields
401Unauthorized - Invalid or missing token
403Forbidden - Insufficient permissions
404Not Found - Song doesn’t exist
500Internal Server Error

Playlists

Organize songs into playlists

Calendar

Schedule songs for services

Build docs developers (and LLMs) love