Sources
A source is long-form raw input for the content pipeline — a voice memo, podcast episode, webinar recording, or pasted transcript. After ingest, Scripe extracts topics — scored chapters of the material — and a topic’s id is what you feed to post generation. Scopes:sources:read / sources:write — grantable to API keys and
OAuth tokens alike (see auth.md §1.2). Deleting
rides sources:destroy, which is OAuth-only and never implied by any
other scope. Full schemas: OpenAPI reference → Sources.
Reading sources
statusisProcessing(ingest in flight),Success(transcript + topics ready), orError. Older rows may carry the legacy terminal valueDone. Treat unknown values asProcessing.textPreviewis the first 2,000 characters of the transcript — the full body is deliberately not exposed over the API (sources can hold customer audio uploaded with no expectation it would leave the dashboard, and hour-long transcripts would dwarf every other response).textPreviewTruncatedandhasFullTexttell you which case you’re in. The preview slices at codepoint boundaries — safe to render as-is.- Storage keys and presigned URLs are never returned.
Topics
GET /v1/sources/{sourceId} includes a topics array once
status is "Success" — best-first by score, each with title,
summary, keyTakeaways, and where it sits in the recording:
scoreis the quality signal;rankingis just the position in the served order (ranking: 1is alwaystopics[0]).fromSecondssays where the topic sits in the recording — an earlier chapter is not a better one.hooksis empty for anything ingested through this API. Hooks are generated by the Scripe dashboard when a human opens a topic; nothing on the API path creates them, and you don’t need one — post generation writes its own.
POST /v1/posts/generations as
source: { "type": "topic", "topicId": "tpc_…" }. The server reads
that topic’s transcript chunk itself — the full transcript is
deliberately never served over this API, so the topic id is the only
way to generate from what the user actually said rather than from the
summary about it. The list endpoint stays cheap and omits topics;
fetch the single source for them.
POST /v1/sources
Two input shapes:
type: "text" — synchronous. You supply the prepared transcript
(1 byte – 1 MB); the row is stored with status: "Success" immediately
and the response is the Source envelope.
type: "file" — asynchronous. First mint an upload handle via
POST /v1/uploads, PUT your bytes to the signed URL,
then reference the handle here. The response is a
Job envelope with type: "SOURCE_INGEST_FILE"; poll
until status: "DONE", then result.sourceId names the new source
(whose own status tracks transcription).
uploadId minted in another workspace returns 404 not_found —
handles are workspace-bound. The file branch is metered by the
AI budget (402 when exhausted).
The uploaded file is not kept. Once the job reaches DONE the
transcript, topics and generated content live on the source; the original
audio, video or document is deleted from storage as part of processing.
For an audio or video source the dashboard shows the transcript without a
player, noting that API uploads are not retained; a document source shows
the transcript with no player and no note. Keep your own copy if you need
the original.
MCP hosts can skip the two-step upload for small files: the
create_source_file tool
takes the bytes inline as base64 up to ~3 MB decoded. A real audio or
video recording is far past that, so it comes through this flow.
DELETE /v1/sources/{sourceId} — two-phase
Permanently deletes a source: the row, the full transcript (paragraphs
and sentences), its topics and their hooks, its knowledge-base copy
(document, chunks, embeddings — knowledge search stops returning the
content immediately), and the stored audio/video/file object, whose
storage quota is released. Irreversible.
A bare DELETE deletes nothing. It returns a proposal
(data.phase: "proposal") naming exactly what will be removed and what
survives, plus a confirmationToken (~5-minute TTL). Show it to the
user; after they explicitly confirm, repeat the request with
?confirmationToken= to execute. The token is bound to this source and
this principal — a mismatched or expired token fails
400 invalid_request (details.reason: confirmation_invalid /
confirmation_expired) and deletes nothing.
kept block:
- Posts generated from the source are kept. They are the user’s
content; only their link to the source goes stale. Removing one is
DELETE-less today — usedelete_postover MCP. - The internal usage-accounting ledger survives — it is historical cost reporting, not source data.
delete_knowledge_doc applies to those rows, enforced
in both phases. Without it the call fails
403 admin_required and nothing is deleted; the proposal counts them in
data.toDelete.workspaceSharedKnowledgeDocuments and warns about them.
Executing emits source.deleted with the source’s
identity only — never the transcript. Requires sources:destroy
(OAuth-only; sources:write and the write alias never imply it).
On MCP the same verb is the two-phase
delete_source tool.
What’s NOT here (yet)
- Full transcript download — previews only, by design.
- File / audio download — storage URLs are private.
- Update — not exposed on any surface today.