Score it. Forge it. Hear about it.
When a song is forged, scored, or gauntleted on SongForgeAI, we POST a signed JSON envelope to the URL you configured. HMAC-SHA256 signing, idempotent envelope ids, no SDK required.
Note: the dispatcher + event contract ship in this build. The per-user subscription UI is a follow-up ticket. Build your receiver against this doc; the “subscribe” button lights up when the UI lands.
Event types
| Type | Fires when |
|---|---|
| song.forged | Forge pipeline finishes producing lyrics + style. |
| song.scored | Eval pipeline writes a composite score (includes the reproducibility seal). |
| gauntlet.completed | Gauntlet refinement finishes. Carries pre + post scores + improved flag. |
Currently exported: song.scored, song.forged, gauntlet.completed
Envelope shape
{
"apiVersion": "v1",
"id": "11111111-2222-3333-4444-555555555555",
"emittedAt": "2026-04-25T08:00:00.000Z",
"event": {
"type": "song.scored",
"songId": "song-abc",
"userId": "user-xyz",
"compositeScore": 82,
"grade": "A",
"percentile": "Top 12%",
"seal": {
"rubricVersion": "1.0.1",
"model": "claude-sonnet-4-20250514",
"temperature": 0.7,
"buildSha": "a1b2c3d4...",
"build": 1215
}
}
}Signing & verification
Every request carries X-SongForge-Signature set to sha256=<hex>where the hex is HMAC-SHA256 of the raw request body keyed by your subscriber secret. Verify with a constant-time compare:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody: string, header: string, secret: string): boolean {
const expected = 'sha256=' + createHmac('sha256', secret)
.update(rawBody, 'utf8')
.digest('hex');
// Constant-time compare to defeat timing attacks.
const a = Buffer.from(header);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Headers
| X-SongForge-Event | The event.type, e.g. song.scored. |
| X-SongForge-Envelope | UUID of this envelope. Use as your idempotency key. |
| X-SongForge-Api-Version | Currently "v1". |
| X-SongForge-Build-Sha | Git SHA of the deploy that emitted the event. |
| X-SongForge-Signature | sha256=<hex>. Omitted when subscriber secret is empty (test mode only). |
Idempotency contract
The envelope id is stable across re-deliveries. If your handler succeeded once, store the id and short-circuit subsequent calls with the same id. Future retry logic (Tier B #22) will produce duplicate deliveries deliberately when network failures hide our success.