Sources
A source is a transcribed file uploaded into a project — typically a voice memo, podcast snippet, or article import. Sources feed the AI pipeline that produces notes and post drafts; they’re not directly visible to end users in the published feed. The v1 API ships a single-resource read endpoint for sources. There is no list endpoint in v1; if you need to enumerate sources, traverse notes (GET /v1/notes) and follow each note’s source attachment when it
ships in v1.x.
GET /v1/sources/{sourceId}
Read a single source row. The transcription body is truncated to the
first 2000 characters for safety — long-form transcripts are excluded
from the API surface, intentionally:
- Sources can hold customer audio they uploaded with no expectation it would leave the dashboard. Exposing the full body would be a surprise.
- Some sources are large (multi-megabyte transcripts of hour-long calls). Pulling them through a JSON response would amplify rate-limit usage without any real client benefit.
Response
Field reference
The S3 storage keys, internal upload identifiers, the original
processing-flusher state, and the secret presigned URLs are
intentionally not in this response. We never return them through the
public API.
Truncation contract
textPreviewTruncated === true→ the preview is exactly 2000 characters and there is more transcript on the server.textPreviewTruncated === falseANDhasFullText === true→ the preview is the full transcript.hasFullText === false→ the source has no transcript yet (still processing or processing failed).textPreviewwill be empty.
Errors
POST /v1/sources
Create a source. Required scope: sources:write.
Two input shapes:
type: "text"— synchronous. The caller supplies the prepared transcript and the row is stored withstatus: Successimmediately. Returns the newSourceenvelope (200).type: "file"— asynchronous. The caller first callsPOST /v1/uploadsto obtain a presigned S3 PUT URL + opaqueuploadIdhandle, PUTs the bytes, then references the handle here. Returns aJobenvelope (200) withtype: SOURCE_INGEST_FILE; pollGET /v1/jobs/{jobId}untilstatus: COMPLETEDand the resultingresult.sourceIdbecomes available.
Request body — type: "text"
Request body — type: "file"
Response — type: "text"
Response — type: "file"
GET /v1/sources/{sourceId} then returns the fully-processed source.
The async path also enforces the per-plan AI spend cap; calls that
would push the daily cost over the cap return 402 spend_cap_exceeded
without enqueueing a job. See docs/api/v1/jobs.md for
the full lifecycle and pricing.
Errors
What’s NOT here (yet)
- List endpoint. No
GET /v1/sources. Plan-side decision; if you have a use case, file a feature request. - Full transcript download. See above.
- File / audio download. Storage URLs are private. The dashboard’s download links are signed and time-limited; we won’t expose them via the API in v1.
- Update / delete endpoints.
PATCH/DELETEare out of scope for v1.