Skip to content
Back to home
API documentation · v1

Lyric Scoring API

Submit any song lyric, get back a 12-metric score from the same rubric that grades every forged song on SongForgeAI. Useful for labeling generated output, A/B-testing your own prompts, or gating publishing workflows on a minimum composite score.

Early access. v1 ships with a single endpoint + sync scoring. Batch scoring + webhooks land in v1.1. Authentication is API-key based (sfai_live_…).

Endpoint

POST /api/v1/score

Authentication

Every request must include a Bearer token in the Authorization header. Keys start with sfai_live_.

Authorization: Bearer sfai_live_a1b2c3d4e5f6…

Alternate header X-SFAI-Key is also accepted. Keys are issued per-user on the Professional tier; contact support to provision.

Request body

JSON with a required lyrics field (50–50,000 chars) and optional genre + title.

curl -X POST https://songforgeai.com/api/v1/score \
  -H "Authorization: Bearer sfai_live_<YOUR_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "lyrics": "I walked the long road home tonight\nThe porch light burned the dark in two\n...",
    "genre": "country",
    "title": "Porch Light"
  }'

Response shape

Successful responses return 200 OK with:

{
  "compositeScore": 78.4,
  "grade": "B+",
  "percentile": "Top 18%",
  "metrics": [
    { "shortName": "Specificity",    "score": 82 },
    { "shortName": "Emotional Truth", "score": 75 },
    { "shortName": "Craft",           "score": 80 },
    ...
  ],
  "wounds": [
    "Bridge lacks perspective shift — feels like a recycled verse.",
    "Final chorus doesn't earn the 'home' landing."
  ],
  "transcendentLines": [
    "The porch light burned the dark in two"
  ],
  "version": "v1",
  "generatedAt": "2026-04-21T12:34:56Z"
}
  • compositeScore — 0-100 weighted sum of the 12 metrics.
  • grade — S+ / S / A+ / … / F per the public grading scale.
  • percentile — "Top N%" label (null for scores below 56).
  • metrics[] — per-metric scores (Specificity, Emotional Truth, Imagery, etc).

Node.js example

const res = await fetch('https://songforgeai.com/api/v1/score', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SFAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    lyrics: draftLyrics,
    genre: 'indie folk',
  }),
});
const data = await res.json();
console.log(`Composite ${data.compositeScore} (${data.grade})`);

Async mode (for batch pipelines)

Scoring a lyric takes 30–60s. For batch workloads, submit async jobs and either poll or receive a webhook when each completes.

// 1. Enqueue
POST /api/v1/score/async
{
  "lyrics": "...",
  "genre": "country",
  "webhookUrl": "https://your-app.com/sfai-webhook"
}
// → 202 { "jobId": "abc...", "status": "queued", "pollUrl": "..." }

// 2a. Poll (auth with the same bearer key)
GET /api/v1/score/jobs/abc...
// → 200 { "status": "succeeded", "result": { ... } }

// 2b. Or receive a webhook (POST to webhookUrl):
// Header: X-SFAI-Event: score.completed
// Body:   { "jobId": "abc...", "status": "succeeded", "result": { ... } }
  • Jobs are tied to the submitting key; only that key can poll.
  • Webhook URLs must be https://. One delivery attempt per terminal state; the poll endpoint is the retry path.
  • Lyric text is echoed back to Supabase for job correlation; excluded from poll responses.

Error codes

StatuserrorMeaning
401missing_api_keyNo token provided.
401invalid_api_key_formatToken malformed.
401unknown_api_keyToken not found in our DB.
401revoked_api_keyToken was revoked.
400invalid_lyricsLyrics missing or too short.
400lyrics_too_longMax 50,000 chars.
429rate_limit_exceeded60 req/hour/key floor.
502eval_output_unparseableUpstream model error. Retry.
503service_not_configuredMaintenance mode.

Rate limits

  • 60 requests per rolling hour per key on the Professional tier.
  • Higher limits available on annual enterprise agreements.
  • Every response includes an X-SFAI-Version header for client-side version pinning.