Skip to content

Summaries API Reference

Reference for the operations an integration needs. For the end-to-end flow, see the Summaries API Guide.

Basics

EndpointPOST https://summaries.video.taxi/api/v1/graphql
AuthAuthorization: Bearer vts_...
Content typeapplication/json
GraphiQLOpen the endpoint URL in a browser. Set the Authorization header to run queries.
IntrospectionEnabled

Authentication

Create an API key in the web app under Account → API Tokens (/account/apitokens). The key is shown only once. It acts as the user who created it: it can see that user’s own summaries and the summaries of their organizations.

The Bearer prefix is optional. A bare vts_... value is also accepted.

Errors

GraphQL errors are returned with HTTP 200 in the errors array. The machine-readable code is in extensions.code.

{
"data": null,
"errors": [{ "message": "Unauthorized access", "path": ["summary"], "extensions": { "code": "UNAUTHORIZED" } }]
}
CodeMeaning
UNAUTHORIZEDMissing or invalid API key. Also returned for summaries the key’s user cannot access.
FORBIDDENQuota exhausted, or the operation is admin-only.
NOT_FOUNDThe referenced summary, version, summary type or organization does not exist.
VALIDATION_ERRORInvalid input or wrong state. See extensions.message. extensions.details holds a JSON-encoded string with per-item details.
CONFLICTConcurrent modification.
SERVER_ERROR, DATABASE_ERROR, STORAGE_ERRORInternal error. The message is always Internal server error.

Scalars

ScalarFormat
UUID"3f2c...-..."
DateTimeRFC 3339, UTC
JSON, JSONObjectArbitrary JSON (value / object)

Queries

me

The user the API key belongs to. You need id for the upload header.

query Me {
me { id username email }
}

organizations

Organizations the user is a member of. Use id as organizationId when creating summaries.

query Organizations {
organizations { id name }
}

summaryTypes

The available summary templates. id is the summaryTypeId used when creating a summary.

query SummaryTypes {
summaryTypes { id label description templateId sortOrder disabledAt }
}

summary

One summary with one of its versions.

query Summary($id: UUID!, $version: Int!) {
summary(id: $id, versionNumber: $version) {
id
title
status
lengthMs
version { versionNumber status summaryTypeId }
}
}
ArgumentTypeDescription
idUUID!Summary ID
versionNumberInt!Version, starting at 1

Returns null if the summary does not exist. Returns NOT_FOUND if the version does not exist.

summaries

Paginated list of accessible summaries, each with its current version.

query Summaries($pagination: PaginationInput, $filter: SummaryFilter, $search: String) {
summaries(pagination: $pagination, filter: $filter, search: $search) {
totalCount
hasNextPage
summaries { id title status createdAt version { versionNumber status } }
}
}
ArgumentTypeDescription
paginationPaginationInputoffset (default 0), limit (default 50, max 100)
filterSummaryFilterFilter by status, versionStatus, summaryTypeId, language
searchStringSearch term

Mutations

generateUploadUrl

Creates a presigned URL for uploading one media file. Also reserves the summary ID.

mutation GenerateUploadUrl($input: GenerateUploadUrlInput!) {
generateUploadUrl(input: $input) { id uploadId uploadUrl expiresInSeconds filename }
}
Input fieldTypeDescription
filenameString!File name, e.g. meeting.mp3
contentTypeString!MIME type. Must equal the Content-Type of the upload.
expiresInSecondsIntURL lifetime. Default 3600.
Result fieldDescription
idThe summary ID for all later calls
uploadIdPass to completeUpload
uploadUrlPresigned S3 URL for the PUT
filenameName the file is stored under. Same as requested.

Upload the file with:

Terminal window
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: audio/mpeg" \
-H "x-amz-meta-user-id: $USER_ID" \
-T meeting.mp3

Both headers are part of the signature. USER_ID is me.id.

completeUpload

Registers the uploaded file on the summary.

mutation CompleteUpload($input: CompleteUploadInput!) {
completeUpload(input: $input) { success summaryId message }
}
Input fieldTypeDescription
idUUID!id from generateUploadUrl
uploadIdString!uploadId from generateUploadUrl
originalFilenameString!Same filename as in generateUploadUrl
languageString!Recording language, e.g. de

createSummaryAsync

Starts processing: demuxing, transcription, speaker and agenda prediction. Returns immediately.

mutation CreateSummary($summary: CreateSummaryInput!) {
createSummaryAsync(summary: $summary) { summaryId versionNumber }
}
Input fieldTypeDescription
idUUID!id from generateUploadUrl
titleString!Display title
languageString!Recording language, e.g. de
originalFilePathString!The uploaded file name (not a path), e.g. meeting.mp3
summaryTypeIdInt!SummaryType.id
organizationIdUUIDOrganization that owns the summary. Omit for a personal summary.
speakerList[SpeakerInput!]Known participants. Enables speaker prediction.
speakerGroupIdUUIDUse the speakers of an existing speaker group.
vocabularyIds[UUID!]Custom vocabularies for transcription
agendaItems[AgendaItemInput!]Agenda items (TOPs). Council/parliament templates only.
detectSpeakersBooleanMatch voices against stored voice samples. Default false.

versionNumber is always 1. The call is idempotent per id.

updateTranscript

Replaces the transcript of a version. Use it to set speaker names or correct text before summarizing.

mutation UpdateTranscript($update: UpdateTranscriptionInput!) {
updateTranscript(update: $update)
}
Input fieldTypeDescription
summaryIdUUID!Summary ID
versionNumberInt!Version
sentences[UpdateTranscriptionSentence!]!The complete transcript
agendaAssignment[AgendaAssignmentInput!]!Agenda item positions. Send [] if unused.

startSummarizing

Starts the LLM summarization for a version. Sets version.status to AWAITING_SUMMARY.

mutation StartSummarizing($id: UUID!, $version: Int!) {
startSummarizing(summaryId: $id, versionNumber: $version, overrideTemplate: false, emptyTops: true)
}
ArgumentTypeDescription
summaryIdUUID!Summary ID
versionNumberInt!Version
emptyTopsBoolean!true if you do not use agenda items. See below.
overrideTemplateBoolean!Only relevant with emptyTops: false. See below.
agendaAssignments[AgendaAssignmentInput!]Agenda item positions in the transcript
transcriptCheckTranscriptCheckModePre-check of the transcript. Default SKIP.

Requires summary.status to be SPEAKER_PREDICTED or AGENDA_PREDICTED, otherwise VALIDATION_ERROR.

emptyTops and overrideTemplate select a variant of the council and parliament templates (de_council, de_council_meeting, de_parliament). For all other templates they have no effect.

emptyTopsoverrideTemplateTemplate used
trueanyThe selected template
falsefalse<template>_tops
falsetrue<template>_chapter

transcriptCheck: STRICT rejects transcripts with too many speaker changes per section (VALIDATION_ERROR, detail code TRANSCRIPT_CHECK_FAILED). ACCEPT_WARNINGS_SWITCH_TEMPLATE starts anyway and may switch to a more robust template. Only council and parliament templates are checked.

changeSummaryVersionType

Changes the template of a version. Only possible while version.status is VOD_LAB_PENDING, i.e. before startSummarizing.

mutation ChangeType($id: UUID!, $version: Int!, $typeId: Int!) {
changeSummaryVersionType(summaryId: $id, versionNumber: $version, newSummaryTypeId: $typeId)
}

createSummaryVersion

Creates a new version, e.g. to summarize the same recording with another template. Copies a transcript, inherits the summary type and becomes the current version.

mutation CreateVersion($input: CreateSummaryVersionInput!) {
createSummaryVersion(input: $input) { summaryId versionNumber }
}
{ "input": { "summaryId": "...", "transcriptSource": { "version": { "versionNumber": 1 } } } }

transcriptSource takes exactly one of original: {} (the unedited transcript) or version: { versionNumber }.

deleteVersion

Deletes one version and its transcript.

mutation DeleteVersion($id: UUID!, $version: Int!) {
deleteVersion(id: $id, versionNumber: $version)
}

deleteSummary

Deletes a summary with all versions. Uploaded files are removed immediately.

mutation DeleteSummary($id: UUID!) {
deleteSummary(id: $id)
}

Types

Only the fields relevant for integrations are listed.

Summary

type SummaryWithVersion {
id: UUID!
organizationId: UUID
title: String!
language: String!
status: SummaryStatus! # transcription pipeline
summaryTypeId: Int!
lengthMs: Int # recording length
createdAt: DateTime!
failedAt: DateTime
originalFileNames: [String!]!
version: SummaryVersion! # the requested version
availableVersions: [SummaryVersion!]!
transcriptResult: TranscriptionResult
summaryResult(applySelector: Boolean): SummaryResult
errorMessage: String # always null for API keys
}
type SummaryVersion {
versionNumber: Int!
status: SummaryVersionStatus! # summarization
summaryTypeId: Int
isCurrent: Boolean!
createdAt: DateTime!
completedAt: DateTime
errorMessage: String # always null for API keys
}

Transcript

type TranscriptionResult {
sentences: [TranscriptionSentence!]!
}
type TranscriptionSentence {
text: String!
startMs: Int! # from start of recording
endMs: Int!
speakerId: String! # speaker label, e.g. "S1" or "Jane Doe"
}

speakerId is a free-text label, not an ID. The transcriber assigns S1, S2, … and you can replace them with names via updateTranscript.

Summary result

type SummaryResult {
data: [JSONObject!] # summary sections
error: String
summaryDocx: String # internal, not downloadable via API key
}

data is a list of sections. Each section maps keys to arrays of values. The keys depend on the template, so render them generically. Every section also contains agendaItemId: [<UUID>] or [null].

Inputs

input SpeakerInput {
firstName: String!
lastName: String!
title: String
party: String
function: String
comment: String
}
input AgendaItemInput {
id: UUID! # client-generated
title: String!
sortOrder: Int!
externalId: String # your own reference
isPrivate: Boolean
}
input UpdateTranscriptionSentence {
text: String!
startMs: Int!
endMs: Int!
speakerId: String!
}
input AgendaAssignmentInput {
title: String!
startMs: Int!
sentenceId: String!
}

Enums

enum SummaryStatus {
IN_CREATION
DRAFT
DRAFT_FINALIZED
DEMUXED
TRANSCRIBED
SPEAKER_PREDICTED
AGENDA_PREDICTED
FAILED
}
enum SummaryVersionStatus {
VOD_LAB_PENDING
AWAITING_SUMMARY
DONE
FAILED
}
enum TranscriptCheckMode {
SKIP
STRICT
ACCEPT_WARNINGS_SWITCH_TEMPLATE
}
SummaryStatusMeaning
IN_CREATION, DRAFTFile uploaded, createSummaryAsync not yet called
DRAFT_FINALIZEDQueued
DEMUXEDAudio extracted
TRANSCRIBEDTranscript available
SPEAKER_PREDICTEDSpeaker prediction done or skipped
AGENDA_PREDICTEDPipeline finished. Agenda prediction done or skipped.
FAILEDProcessing failed
SummaryVersionStatusMeaning
VOD_LAB_PENDINGWaiting for startSummarizing (named after the web editor, “VOD Lab”)
AWAITING_SUMMARYSummarization running
DONEsummaryResult available
FAILEDSummarization failed

Limits

File sizeUp to 2 GB recommended (web app limit). The API does not check the size, but files over 5 GB fail.
FormatsVideo: mp4, m4v, mov, mpg, mpeg, ts, webm, 3gp, avi, flv, wmv, mxf. Audio: wav, mp3, m4a, aac, flac, opus, wma, gsm.
Languagede. Other codes are not validated and may fail transcription.
Page sizesummaries: max 100
NotificationsNone for API clients. Poll.
ExportsDOCX/PDF downloads are only available in the web app.