Guide
Voice notes
These routes are built for a client that owns its own data and syncs it: a phone that records offline and reconciles later. That shapes almost everything about them, starting with who decides the id.
You choose the id
Unlike everything else in this API, you do not POST and receive an id back. You pick one and PUT the note at it. The same call creates or replaces, so a client that recorded something offline can send it whenever it next has a connection, without a round trip first.
PUT/voice-notes/{note_id}
curl -X PUT "$MORSE/voice-notes/$ID" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "9d4e7c21-3b6f-4a05-8e92-5c1d0f8a2b64",
"status": "ready",
"created_at": "2026-10-02T10:30:00+05:30",
"title": "Notes after the pricing call",
"duration_seconds": 94
}'It replaces the whole note. To change part of one, use PATCH, which leaves the fields you do not send alone.
Not clobbering an edit
Two devices syncing the same note will eventually both write it. Send If-Unmodified-Since with the time you last saw, and the write is refused if someone got there first, rather than silently overwriting them.
PATCH/voice-notes/{note_id}
curl -X PATCH "$MORSE/voice-notes/$ID" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-H "If-Unmodified-Since: Wed, 02 Oct 2026 05:00:00 GMT" \
-d '{ "title": "Pricing call, follow-ups" }'Listing and paging
Newest first, a page at a time, with a cursor rather than an offset.
GET/voice-notes
curl "$MORSE/voice-notes?limit=20&status=ready" \
-H "Authorization: Bearer $MORSE_TOKEN"| Parameter | What it does | Note |
|---|---|---|
limit | How many to return. | A page at a time, newest first. |
cursor | Where the last page stopped. | Absent on the first call. |
since | Only what changed after this time. | For catching up, not for browsing. |
status | Narrow to some states. | Repeatable. |
q | Search the text. | |
include_deleted | Include soft-deleted notes. | Needed to learn a note was deleted. |
For syncing rather than browsing, ask only for what changed, and include the deleted ones, or your client will never learn that a note went away.
curl "$MORSE/voice-notes?since=2026-10-02T05:00:00Z&include_deleted=true" \
-H "Authorization: Bearer $MORSE_TOKEN"The audio
The recording is uploaded separately from the note, in the same three steps as everything else, with one addition: you declare a sha256, so Morse can tell whether what arrived is what you sent. There is also an abort call, for giving up cleanly on a transfer that will not finish.
GET /voice-notes/{id}/audio redirects to a short-lived link to play it back. The full sequence is in Uploads.
Keeping in step
Changes stream as server-sent events. There is no replay buffer: every connection opens with a resync, which is the server telling you to go and fetch what you missed rather than replaying it.
GET/voice-notes/events
curl -N "$MORSE/voice-notes/events" \
-H "Authorization: Bearer $MORSE_TOKEN"So the pattern is: open the stream, take the resync as a cue to call GET /voice-notes?since=…, then follow the events until the connection drops, at which point you do it again.
Deleting
- Soft by default. A deleted note is restorable for thirty days, then erased by a sweep.
- 410, not 404. Fetching one that has been deleted tells you it existed and is gone, which is what a syncing client needs to hear.
Speakers
Morse keeps a voiceprint per known speaker so it can name who is talking. These are yours: GET /voice-notes/speakers lists them, PUT /speakers/{id} saves one, and DELETE /speakers/{id} forgets one.
DELETE /voice-notes/speakers?all=true erases every voiceprint Morse keeps for you. The flag is required precisely because the call is not reversible.A note can also be pulled out as Markdown or plain text: GET /voice-notes/{id}/export?format=markdown. Full schemas are under Reference → Voice-notes.