API Reference

The sayer API uses NIP-98 HTTP authentication. Every request must include a signed Nostr event in the Authorization header. Paid jobs require a Lightning invoice to be settled before processing begins.

Authentication

All API endpoints require NIP-98 authentication. Create a kind 27235 Nostr event with u and method tags, sign it, base64-encode the JSON, and send it as a Bearer-style header.

Authorization: Nostr <base64-encoded-signed-event>

The event timestamp must be within 60 seconds of server time. Your pubkey must be in the server's allowlist.

GET /v1/pricing

Returns the current pricing configuration. In paid mode, the price is calculated per chunk of words.

Response

{
  "free_mode": false,
  "unit": "words",
  "price_per_chunk": 79,
  "chunk_size": 50
}
GET /v1/voices

Lists all available TTS voices. Voices with embeddings are cloned from uploaded samples.

Response

{
  "voices": [
    { "name": "alice", "has_embedding": true },
    { "name": "default", "has_embedding": false }
  ]
}
POST /v1/jobs

Submit text for synthesis. In paid mode, a Lightning invoice is returned and must be paid before the job begins processing. Admin pubkeys bypass payment entirely.

Request body

{
  "text": "The text to synthesize.",
  "voice": "alice",
  "speed": 1.0,
  "language": "en",
  "format": "mp3"
}

Only text and voice are required. Other fields are optional.

Response (paid mode)

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "awaiting_payment",
  "voice": "alice",
  "invoice": "lnbc...",
  "amount_sats": 79,
  "created_at": "2025-01-15T10:30:00Z"
}

Response (free mode / admin)

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "voice": "alice",
  "created_at": "2025-01-15T10:30:00Z"
}
GET /v1/jobs

Lists all jobs belonging to the authenticated pubkey.

Response

{
  "jobs": [
    {
      "id": "550e8400-...",
      "status": "completed",
      "created_at": "2025-01-15T10:30:00Z",
      "completed_at": "2025-01-15T10:31:00Z",
      "result_url": "https://sayer.nostr.xyz/v1/jobs/550e8400-.../result"
    }
  ]
}
GET /v1/jobs/:job_id

Returns the current state of a job. Poll this endpoint to track progress. If the job is awaiting payment and the invoice has been settled, the server automatically advances the job to processing.

Job statuses

awaiting_payment
processing
completed
failed
GET /v1/jobs/:job_id/result

Downloads the synthesized audio file. Only available for completed jobs. Returns the audio stream with the appropriate Content-Type header (typically audio/mpeg).

Returns 409 Conflict when the job is not yet completed.

GET /health

Health check endpoint. Requires authentication.

Response

{ "status": "ok" }