letzwhisper

Montréal GPU · no rush

Send audio.
Get text.

Upload a file or POST it to the API. We queue it on a GPU in Montréal — not OpenAI — and you watch it finish, download txt/srt/json, or take a webhook.

meeting-22.m4a queued → done
SPEAKER_00: Bonjour.
SPEAKER_01: Allô — on commence ?

[00:00:12] SPEAKER_00: Oui. On parle du trimestre.

How it works

01

Upload or POST

Drop a file in the app, or send multipart audio to the API with your key.

02

We transcribe on our GPU

A background job on a 4060 Ti in Montréal runs Whisper. One job at a time. Not OpenAI.

03

Live, webhook, or both

Watch the show page. Poll GET for txt/srt/json. Or give us a webhook URL.

Formats: plain text, [HH:MM:SS] timestamps, SRT, JSON speaker arrays.

API

Always async. POST returns 202. Poll or wait for the webhook — we will not hold your HTTP request open while the GPU works.

Create

curl -X POST https://whisper.byel.dev/api/v1/transcriptions \
  -H "Authorization: Bearer lw_live_…" \
  -F audio=@meeting.m4a \
  -F webhook_url=https://example.com/hooks/whisper \
  -F diarize=true \
  -F timestamps=false

# 202
{"id":"t_01J…","status":"queued"}

Live poll

GET /api/v1/transcriptions/t_01J…
GET /api/v1/transcriptions/t_01J….txt
GET /api/v1/transcriptions/t_01J….srt
GET /api/v1/transcriptions/t_01J….json

# .txt / .srt return 409 while processing

Webhook body

{
  "id": "t_01J…",
  "status": "completed",
  "language": "fr",
  "text": "SPEAKER_00: Bonjour.\nSPEAKER_01: Allô.",
  "srt": "1\n00:00:00,000 --> 00:00:02,100\nSPEAKER_00: Bonjour.\n\n",
  "segments": [
    {"start": 0.0, "end": 2.1, "text": "Bonjour.", "speaker": "SPEAKER_00"}
  ]
}
# Header: X-Letzwhisper-Signature: sha256=HMAC(api_token, raw_body)

Privacy

Audio is stored so the web host and the GPU worker can both see it, then transcribed on a machine in Montréal. Nothing is sent to OpenAI. French, English, Portuguese, and Spanish are auto-detected. One consumer GPU, one queue — overnight batch is an honest product, not a bug.