Transcript endpoints

List a channel's transcripts, read one with every line and its speaker, and choose where it goes, through the REST API.

Updated

New in November 2026

Paths are relative to https://api.fishcamp.space/api/v1 and all need the X-Workspace-Id header. API keys need the read scope to read transcripts; choosing where one goes needs a person. How transcription and routing work is in Transcription and AI routing.

The transcript object

{
  "id": "3f2d9c1e-5b7a-4c2e-9a0b-6d8e1f4a2c7b",
  "channelId": "0b6f3c55-2a51-4e0a-a3d6-6a3f1f2e9d10",
  "startedAt": "2026-11-05T15:00:12.000Z",
  "endedAt": "2026-11-05T15:25:40.000Z",
  "status": "DONE",
  "action": "run_devops_agent",
  "confidence": null,
  "routedBy": "7a1c2e3f-4b5d-4e6f-8a9b-0c1d2e3f4a5b",
  "routedAt": "2026-11-05T15:26:03.000Z",
  "segmentCount": 48,
  "participants": ["Maya Lopes", "Theo Park", "Ana Souza (guest)"],
  "result": {
    "executionId": null,
    "agents": [{ "agentId": "e5c4b3a2-1f0e-4d9c-8b7a-6f5e4d3c2b1a", "name": "Scout", "ok": true, "status": 202, "error": null }]
  }
}
FieldDescription
idThe transcript's ID. One transcript per audio room session.
statusACTIVE while the room is open and being transcribed, PROCESSING while Dcision decides, then DONE or FAILED.
actiondiscard, save_to_opensync, run_devops_agent (Send to agents), or review while it waits for a person.
confidenceHow sure Dcision was, from 0 to 1, or null when a person decided.
routedBydcision, system (nothing was transcribed), or the profile ID of the person who chose.
participantsEveryone who spoke. Guests have "(guest)" after their name.
resultWhat happened: opensync.path and opensync.spaceId after a save; agents, one item per agent with agentId, name, ok, status and error, after a handoff; error when it failed; reason when it's waiting for a person, for example because a guest spoke and Dcision picked agents.

Read a transcript adds segments: every line with its speakerName, startMs and endMs (milliseconds since the room opened) and text.

List transcripts

GET /channels/:channelId/transcripts

The 20 latest transcripts of the channel's audio rooms, newest first: when each call happened, who spoke, and what was decided for it (discarded, saved to OpenSync, sent to agents, or waiting for a person). A channel you can't see answers 404.

curl "https://api.fishcamp.space/api/v1/channels/0b6f3c55-2a51-4e0a-a3d6-6a3f1f2e9d10/transcripts" \
  -H "Authorization: Bearer cwk_YOUR_KEY" \
  -H "X-Workspace-Id: YOUR_WORKSPACE_ID"

Read a transcript

GET /transcripts/:transcriptId

One transcript: every line with the name of who said it, plus the routing decision. Use the IDs from the list above. A transcript from a channel you can't see answers 404.

curl "https://api.fishcamp.space/api/v1/transcripts/3f2d9c1e-5b7a-4c2e-9a0b-6d8e1f4a2c7b" \
  -H "Authorization: Bearer cwk_YOUR_KEY" \
  -H "X-Workspace-Id: YOUR_WORKSPACE_ID"

Transcripts contain text only: the audio is never stored, so there's nothing to download but the words.

AI agents can read the same data with the MCP tools list_transcripts and read_transcript.

Choose where a transcript goes

New in November 2026
POST /transcripts/:transcriptId/route

People who can see the channel: requests with an API key get 403. Use it to decide a transcript that's waiting for a person, to change Dcision's choice, or to try a failed action again.

actionWhat happens
discardMarks it as discarded. What was already saved or sent stays where it went.
save_to_opensyncSaves it as a note in the workspace's OpenSync space.
run_devops_agentSend to agents: delivers it to the channel's agents that take transcript handoffs.
curl -X POST "https://api.fishcamp.space/api/v1/transcripts/3f2d9c1e-5b7a-4c2e-9a0b-6d8e1f4a2c7b/route" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -H "X-Workspace-Id: YOUR_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"action": "run_devops_agent"}'

Returns 200 with the transcript, without its lines. When the action itself fails, for example because OpenSync isn't connected or no agent takes handoffs, the answer is still 200, with "status": "FAILED" and the reason in result.error. The timeline gets a line with the result either way.

ErrorWhen
409 transcript_busyThe room is still open or just closed, Dcision is still deciding, or someone else's choice is running. Only one choice runs at a time.
409 transcript_emptyNothing was transcribed.
422 validation_erroraction isn't one of the three above.

On this page