Skip to main content

Changelog

v1.38.0 - Offline copies of the knowledge base

  • A knowledge base can be exported as a static site. POST /v1/knowledge-base/exports builds a ZIP with branding, sections, articles, images, each article's exported video and a client-side search index; it opens from index.html with no server. Pick languages, restrict to tagged articles, and choose whether to include videos (a missing or stale export is rendered first and metered like any export). Poll GET /v1/knowledge-base/exports/:id; the list carries presigned download links and a stale flag once the content moves on. See Offline export.

v1.37.0 - Tags on knowledge base articles

  • Articles can carry tags. Tags are private labels for filing, never shown on the public site, and the way you will pick articles for an offline export. The list lives on the knowledge base: PATCH /v1/knowledge-base with the full tags array creates, renames and deletes in one call, and a deleted tag is pulled from every article. Assign with tagIds on article create and update; filter the list with tagId. tagIds stays editable on a locked article. See Tags.

v1.36.0 - Language families, a shared training across languages, and the whole planning half of a lock

  • Translating a package now links the two. Both carry a languageGroup — the id of the first package in the family — so "this instruction in every language" is one request: GET /v1/videos?languageGroup=vid_abc123. translatedFrom records the one hop. Both are null on packages translated before this shipped; no migration invented families for them. See Language families.
  • A translated package now has a training, and it is the SAME training. It used to have none. The translated package points at the source's module and the module gains a translation in the target language, rather than being copied. A copy per language would double every row of the Training Planner and split one requirement's qualification records across several trainings. See What a translation creates.
  • In the Knowledge Base, a translated article now plays the video in the reader's language when the package was translated into it, instead of the source-language video under translated text.
  • The lock carve-out covers the whole planning half. settings.availableFrom, settings.availableUntil, settings.qualificationValidDays, settings.requiresTrainerApproval and settings.recordAttempts join settings.mandatory and keywords as editable on a locked module. settings.participantIdentity deliberately stays frozen: it decides whether a result can be attributed to a person, which is evidence. See Planning metadata and locks.
  • Approvers are emailed when a planning field moves after they approved it, through the API as well as the app. A signature should never be quietly amended underneath the person who gave it.
  • Every one of those fields is now in the change history, not just mandatory and keywords.
  • Fixed: a saved planning change could look unsaved in the app. Switching to another tab in the training editor and back rebuilt the fields from the module as it was when the page loaded, so a change that had been saved showed its old value — and setting it "again" then recorded nothing, because nothing had changed. The values now survive a tab switch.
  • MCP: list_videos accepts languageGroup; languageGroup and translatedFrom added to the video output shape.

v1.35.0 - Archived trainings, several keywords, and a record of what a lock lets through

Three changes to the planner and to what a locked module keeps.

  • includeArchived=true now actually shows archived trainings. It did not: readiness, which defaults to the narrowest option with trainings behind it, ran afterwards and removed them again, because a retired training is rarely still published. Readiness no longer applies to archived trainings, since a training answers "is this finished" by being archived. See Which trainings belong in a plan.
  • The keyword filter takes several. ?keyword=Safety&keyword=Annual or ?keywords=Safety,Annual. Several keywords are an OR. One keyword behaves exactly as before. See Keywords.
  • Changes to settings.mandatory and keywords on a locked module are recorded - who, when, and whether the module was locked at the time. Those two fields are the only ones a lock lets through, so an approval that can be amended afterwards needs a trail. Visible in the app on a training's Change history tab. See Planning metadata and locks.
  • Fixed: PATCH /v1/modules/:id replaced the whole settings object. A body carrying only {"settings": {"mandatory": true}} dropped recordAttempts, participantIdentity and qualificationValidDays from that module. Settings now merge, so a partial update changes only the keys it names.
  • MCP: training_planner accepts an array for keyword.

v1.34.0 - Twenty more languages

GET /v1/languages now returns 74 languages, up from 54. Nothing else changed: the same codes still work, and the list is served from the registry the product uses, so no client that reads it needs a change.

  • New codes - az Azerbaijani, kk Kazakh, ky Kyrgyz, mk Macedonian, be Belarusian, bs Bosnian, is Icelandic, ga Irish, cy Welsh, gl Galician, lb Luxembourgish, as Assamese, sd Sindhi, ps Pashto, jv Javanese, ceb Cebuano, ha Hausa, so Somali, ny Chichewa, ln Lingala. Accepted anywhere language is - Analyze, Translate, Voiceover and Update Video.
  • ps and sd are right-to-left, and are treated as such in subtitles and articles.
  • MCP: list_languages returns them with no change - it reads the same endpoint. If you cached the list, refresh it.

v1.33.0 - A decision, not a checkbox

The planner's "not applicable" checkbox answered two questions with one blank box: this combination was ruled out, or nobody had looked at it yet. It is now three states. See Which combinations have to be trained.

  • applicability on every planner row - undecided (the state every combination starts in), applicable (somebody deliberately ruled it in) or not_applicable (somebody deliberately ruled it out). Filter the grid with GET /v1/modules/planner?applicability=undecided.
  • PUT /v1/modules/planner/deadline accepts applicability. Send undecided to erase a decision. dueAt and the decision stay independent.
  • notApplicable still works, everywhere it did. true is not_applicable, false is undecided, and it is still returned on every row. applicability wins when both are sent. Cells written before this release read correctly with no migration.
  • includeArchived=true brings retired trainings back into the planner, flagged archived on the row. They stay out by default - a retired training is not work still to do - but a training somebody completed before it was withdrawn is still a record they may have to produce. The response carries archivedCount either way. This reverses "archived trainings are no longer in the planner at all" from v1.31.0: the right answer was a filter, not a rule.
  • The CSV export's N/A column is now Decision (-, A, N/A), plus an Archived column.
  • MCP: training_planner takes applicability and includeArchived; set_training_deadline takes applicability.

v1.32.0 - One package, one name

A workspace can now insist that a video, its help article and its training carry the same title. Off by default, so nothing you already named moves.

  • naming.syncPackageTitles workspace setting. With it on, an article or training generated from a video takes the video's title verbatim instead of writing its own.
  • PATCH /v1/videos/:id cascades a rename. Renaming a video renames its help article and its linked training module in the same request. A locked module is skipped - a lock is irreversible, and an approved round is locked - and the rename still succeeds. Renaming a locked video is still refused with 423, unchanged.
  • Titles edited by hand are left alone. The setting governs generation and rename, nothing else.
  • Knowledge Base articles are deliberately not renamed. A published article's title drives its public slug, and a video rename must not churn live URLs.
  • MCP: update_video renames the package when the setting is on. No request or response fields changed.

v1.31.0 - A planner you can narrow, and a lock that knows what it protects

The planner shows every training against every person, which is what makes it useful and what makes it long. See The planner.

  • readiness=published|approved|all on GET /v1/modules/planner. A training appears the moment it is defined, so the default now excludes work in progress. Omit the parameter and the server picks the narrowest option that actually has trainings behind it, then reports it back as readiness with readinessCounts for all three.
  • Archived trainings are no longer in the planner at all. Archived means retired. The history stays in the analytics endpoints.
  • keywords on a module — up to 20 tags, 40 characters each, set with PATCH /v1/modules/:id. GET /v1/modules/planner?keyword=Safety filters by one, matched whole and case-insensitively, and the response carries every keyword in use in the workspace.
  • settings.mandatory and keywords are now editable on a LOCKED module. A lock freezes the evidence; who must take a training and how it is filed is not evidence. Everything else still returns 423, and a request mixing the two is rejected whole. See Planning metadata and locks.
  • MCP: training_planner takes readiness and keyword; update_module takes keywords.

v1.30.0 - Filtering for what is missing

Two filters on GET /v1/videos, both for finding the gap rather than the record. See List videos.

  • approval=pending|approved|rejected|withdrawn — the latest approval decision on the package. Paired with backup=none it is the pre-audit check: signed off, with nothing filed offline.
  • kb=published|not_published|none — Knowledge Base state. not_published covers a video with no article and one whose article is still a draft; none is the narrower "no article was ever created from it". Resolved from the articles on every request, so it cannot go stale after one is archived or deleted.
  • MCP: list_videos takes approval and kb.

v1.29.0 - Planning a large grid

The planner is a full cross-product, which is what makes it useful and what makes it long. These are the four ways to cut it down. See Training Modules.

  • mandatory on a trainingPATCH /v1/modules/:id with { "settings": { "mandatory": true } } marks it compulsory for everyone. GET /v1/modules/planner?mandatory=true then answers "who is missing something they must have" in one call.
  • notApplicable on a cellPUT /v1/modules/planner/deadline with { "notApplicable": true } rules out a combination that will never be relevant. Ruled-out cells are hidden unless you pass includeNa=true, and never count as overdue. Reversible at any time. dueAt and notApplicable are independent: sending one leaves the other alone.
  • Sortingsort=urgency|training|person|status|expires|deadline with dir=asc|desc. Rows with no value for the sorted column sort last in both directions.
  • Planner rows now carry mandatory and notApplicable.
  • MCP: training_planner takes mandatory, includeNa, sort and dir; set_training_deadline takes notApplicable, and dueAt is now optional.

v1.28.0 - Setup instructions on saved logins

A saved login now carries the steps the recorder performs on that site before every recording and screenshot, off camera. See Setup instructions.

  • setupPrompt on every item from GET /v1/recorder-sessions - null when unset.
  • New PATCH /v1/recorder-sessions/:domain - { "setupPrompt": "..." } sets it, null clears it. Up to 2000 characters. 404 when the domain has no saved login. Requires recordings:write.
  • A recording started with its own setupPrompt still wins for that job; the session's is unchanged.
  • MCP: list_recorder_sessions returns setupPrompt; new update_recorder_session tool.

v1.27.0 - The training planner

Who has not done a training, which every other training endpoint is structurally unable to answer. See Training Modules.

  • New GET /v1/modules/planner — one row per (training, person), most urgent first. Includes people who have never attempted anything, so status: "not_started" finally has somewhere to appear. daysToDue is negative once a deadline has passed.
  • New PUT /v1/modules/planner/deadline — the date by which one person must complete one training. dueAt: null clears it. A deadline is an expectation, not a record, so it can be set on somebody who has never attempted the training.
  • New GET and POST /v1/modules/people — the training roster. Adding somebody before they have trained at all is what makes "has never done it" visible for a new employee. Idempotent on email.
  • Statuses: passed, renewed, expired, awaiting_signoff, in_progress, not_started. renewed means a qualification lapsed and was earned again; renewing early, before expiry, is not a gap and stays passed.
  • unattributedAttempts reports attempts recorded without an email, which belong to nobody on the grid rather than being silently dropped.

v1.26.0 - Knowledge Center sub-sections

Sections in the Knowledge Center can now nest one level deep. See Sub-sections.

  • New parentId on every section returned by GET /v1/knowledge-base/sections, create, update and reorder. null for a top-level section, otherwise the id of its top-level parent. Sections created before this release come back with parentId: null.
  • Accepted on POST and PATCH /v1/knowledge-base/sections. The parent must exist, belong to the same knowledge base, and be top-level; a section cannot be its own parent; a section that already has sub-sections cannot be nested. Each of these is a 400 validation_error.
  • DELETE /v1/knowledge-base/sections/:id now returns 400 while the section still has sub-sections, alongside the existing 409 while it still holds articles.
  • position orders siblings. reorder numbers top-level sections and each parent's sub-sections as separate groups, so a mixed list never interleaves them.
  • Nothing moves: slugs stay unique across the whole knowledge base and public URLs stay flat, so nesting a section never breaks a link.
  • MCP: list_kb_sections, create_kb_section, update_kb_section and reorder_kb_sections carry parentId in their input and structured output.

v1.25.1 - Package backup state on videos

Which published content has no offline backup yet, in one query.

  • New packageDownload object on list and get, recording when a video's package ZIP was last built and by whom. null means never.
  • New backup filter on list: none for videos that have never had a package built, taken for those that have.
  • Stamped when the ZIP finishes building and its link is sent, not when someone clicks that link. The build is what answers "has a backup been taken".

v1.25.0 - Read-only projects

A project folder can now be readable by the whole workspace while only a named few can change what is in it. See Project Access.

  • New "readonly" value for access.mode on create and update, alongside the existing workspace and restricted. memberIds now means "who may see it" under restricted and "who may change it" under readonly.
  • New folder_read_only error code, 403. Returned by every write against an item in a read-only project: editing, generating, translating, voiceover, locking, archiving, requesting approval, publishing, moving, duplicating and deleting, plus renaming or deleting the project.
  • Reads are untouched. Listings include the project, videos open, and the package ZIP still downloads - a read-only project is meant to be consumed.
  • Deciding an approval and commenting stay open to anyone who can see the project. Approvers are named explicitly, and a comment is feedback about a package rather than part of it.
  • 403 here, not 404: the caller can see the item, so it says why. A restricted project keeps answering 404.
  • Filing something new into a project - a video, a Studio project, a remix - is now checked as a write against the target project on every path that accepts a projectId.

v1.24.1 - Studio projects know where they came from

A video in the app can now be opened directly in Studio, which rebuilds it as editable layers. When that happens the resulting Studio project records which video it came from.

  • New sourceVideoId on GET /v1/studio/projects and the single-project endpoint. It is the id of the video the project was imported from, or null.
  • Informational only. The video is a separate object: it is not locked, hidden or otherwise changed by the Studio project pointing at it, and it may since have been deleted.
  • Set once, when the project is created. It is not writable, and duplicates and templates made from such a project do not inherit it - the relation belongs to the one project built from that video.

v1.24.0 - Project access

A project folder can now be limited to specific people instead of the whole workspace. See Project Access.

  • New access object on create, update, get and list. { "mode": "workspace" } is the default every project already had; { "mode": "restricted", "memberIds": [...] } limits it.
  • A restricted project, and every video filed in it, returns 404 not_found for anyone who can't reach it - not 403. Listings simply omit it.
  • Workspace owners and admins always have access, listed or not. Otherwise a project could be stranded with nobody able to reach it.
  • API keys are not subject to restrictions - a key authenticates as a workspace, not a person. OAuth tokens are, and see exactly what their user sees in the app.
  • Setting access needs the permission to manage members. An update that omits it leaves the current setting alone, so a rename can't quietly open a project up.
  • Videos that aren't filed in a project stay visible workspace-wide, and existing share links keep working.
  • The check covers every endpoint that reads or acts on a video - analyze, export, translate, voiceover, article, subtitles, script, download, update, delete, governance, and job polling - plus the ones that pull a video's content elsewhere: remixes, module generation, course creation and knowledge-base/articles/from-video. Moving a video into a restricted project is checked too.
  • Studio projects, remixes and courses are filed in projects as well, and hide with them - on GET /v1/studio/projects, GET /v1/remixes, GET /v1/courses and each of their single-item endpoints.

v1.23.0 - AI Recorder on every paid plan

The AI Recorder is no longer an add-on you have to ask for. Every paid plan includes it, so POST /v1/recordings works on any workspace that isn't on the free plan.

  • A free-plan workspace still gets 403. So does a workspace whose subscription has lapsed, for as long as it stays lapsed.
  • New 429 - two recordings run per workspace at a time. Recording browsers are a shared pool, so a start beyond that is refused rather than queued indefinitely. A job that is waiting for a free browser reports progress.step: "queued".
  • A 429 returns rate_limit_exceeded, not limit_exceeded. It means wait, not buy credits.

v1.22.1 - AI provenance for courses and Studio

The Art. 50(2) marking now covers the two remaining places Vidocu writes text.

  • Courses - aiProvenance on GET /v1/courses, GET /v1/courses/:id and GET /v1/courses/:id/storyboard (per module), plus an X-Content-Provenance header on the storyboard response and the record on the public course share payload. Generating a module now also marks the narration on the resulting video, so every video surface inherits it.
  • Studio - aiProvenance on GET /v1/studio/projects/:id when the assistant wrote text in the project. Recorded at project level and server-owned: the editor only reports that the assistant acted, and the record is stamped server-side so it can't be forged.

Still nothing visible, still no setting.

v1.22.0 - AI provenance

Text Vidocu generates is now marked as machine-generated in a machine-readable form, meeting our Article 50(2) obligation under the EU AI Act ahead of the 2 December 2026 date.

  • aiProvenance on the article and subtitles responses, plus an X-Content-Provenance header on both and on download.
  • The same record is written into each export format's own metadata slot - XMP for PDF, custom document properties for DOCX, <meta> tags for HTML and knowledge-base pages, a NOTE block for WebVTT, and manifest.json for the package ZIP.
  • humanEdited is derived by comparing the stored text against the hash taken at generation, so it reflects what actually happened rather than a flag someone had to remember to set.

Nothing visible changed. No badge, no label, no difference in how an article, PDF or knowledge-base page renders. There is no setting: the duty falls on us as the provider of the generation system, not on the workspace.

SRT and Notion have no metadata slot that leaves the content untouched, so their marking travels alongside - header, manifest and sidecar. The reasoning is written up in full.

v1.19.1 - Custom caption height

  • captions.positionPercent on export - with position: "custom", place burned-in captions anywhere from 0 (as high as they go) to 100 (as low as they go) instead of only top, middle or bottom.
  • Both ends stop at a safe margin and the caption is anchored by its own edge, so no value can push it off screen. Out-of-range numbers are clamped.
  • top, middle and bottom render exactly where they always did.

v1.21.0 - Studio export

POST /v1/studio/projects/:id/export renders a Studio timeline to video. Returns a job to poll; counts as one export against the plan.

Together with the timeline endpoint this closes the loop: build a timeline over the API, render it, download the result - no editor required.

The render logic moved to lib/studioExport.ts so the dashboard and the API run the same code rather than two copies of the Remotion composition props.

v1.20.0 - Studio

The multi-track editor's projects.

  • Projects - list, create, get, rename, delete. The list returns timeline counts; a single project returns tracks, clips and media in full.
  • Duplicate - copies the timeline, never the share link or export state.
  • Share links - idempotent minting, with visibility as a separate switch so revoking doesn't break the URL.
  • Templates - the workspace's own plus the global gallery.

The timeline is read-only through the API: it's a large interdependent document the editor owns. Exporting isn't exposed yet - it needs the same extraction Remix export went through.

New scopes: studio:read, studio:write.

v1.19.0 - Remix export and regenerate

The two Remix endpoints v1.17.0 shipped without.

  • POST /v1/remixes/:id/export - blog, LinkedIn and X return their content immediately; shorts and trimmed cuts start a render and return a job.
  • POST /v1/remixes/:id/regenerate - rewrite a text output from the analyzed transcript. Free, and it replaces the existing draft.

Both run the same code as the dashboard rather than a second copy, so the lambda payloads and the generation prompts exist in exactly one place.

v1.18.0 - Training Modules + Brand Kit assets

  • Training modules - generate, edit, lock, translate, and the compliance records around them: attempts, passers, trainer sign-offs and workspace analytics.
  • POST /v1/modules/:id/submit records a graded attempt. Grading runs server-side against the answer keys, so an LMS integration never needs them.
  • Answer keys are included by default on a single module and excluded everywhere else; pass forLearner=true for the learner-safe shape.
  • Brand Kit assets - GET|POST /v1/brand-kit/assets, DELETE /v1/brand-kit/assets/:id.

New scopes: modules:read, modules:write.

v1.17.0 - Remix

One long video into shorts, a blog post and social copy.

  • Create and analyze - POST /v1/remixes, POST /v1/remixes/:id/analyze. Sourced from a workspace video or an external URL.
  • One analysis per workspace at a time. A second request returns status queued rather than failing, and starts on its own.
  • Read, update, delete plus GET /v1/remixes/:id/exports.

Starting an export and regenerating drafted copy are not exposed yet - both need extracting out of their session-bound handlers first, so the API and dashboard run the same code.

New scopes: remixes:read, remixes:write.

v1.16.0 - AI Recorder

Describe a flow, get a screen recording.

  • Start a recording - POST /v1/recordings. Long-running; poll the job.
  • Status carries two distinct failure shapes: aborted (no usable video) and partial (a video that doesn't show the whole flow). Don't treat a partial recording as finished.
  • POST /v1/recordings/:jobId/input - hand over a one-time code or 2FA challenge when the agent pauses for one.
  • Download returns a time-limited URL rather than the bytes.
  • Saved logins - GET /v1/recorder-sessions, DELETE /v1/recorder-sessions/:domain. Stored cookies are never returned.

Charged per minute of finished video on completion, with a preflight balance check. Failed and aborted jobs are free.

New scopes: recordings:read, recordings:write.

v1.15.0 - Knowledge Center

The hosted help site, end to end.

  • Knowledge base - GET|POST|PATCH|DELETE /v1/knowledge-base. One per workspace, so it's a singular resource.
  • Sections and articles - full CRUD, cursor-paginated listing, Markdown content.
  • POST /v1/knowledge-base/ask - retrieval-grounded answers with citations, for support-bot integrations. Answers from your published articles, not from general model knowledge.
  • Import from video, translation, reindex, redirects and analytics.

Locked articles are frozen to sectionId, state and seo; publishing respects the source video's approval round.

Knowledge Center AI operations bill against the add-on's own AI credit pool, not the workspace credit balance.

New scopes: knowledge_base:read, knowledge_base:write.

v1.14.0 - Locks & Approvals

The controls that make a video library auditable.

  • Locks - POST|DELETE /v1/videos/:id/lock. Freezing cascades to the linked training module and KB articles. Unlocking is refused while an approval round is open.
  • Approvals - request, list, decide, withdraw. Every named approver must approve; one rejection fails the round. Only a named approver can decide, and only once.
  • Comments - review notes, optionally pinned to a timestamp.

Actions record who performed them: OAuth tokens are attributed to their user, API keys to the workspace owner. For per-person attribution in an audit trail, use OAuth rather than a shared key.

New scopes: locks:write, approvals:read, approvals:write, comments:read, comments:write.

v1.13.0 - Courses

Turn a document or an existing video into a set of modules, each of which becomes one video.

  • Courses - POST /v1/courses from a PDF, DOCX, PPTX, Keynote, TXT or an existing video; list, read, update and delete.
  • Storyboard - GET|POST /v1/courses/:id/storyboard. The read includes omissions (source content deliberately left out) and warnings, so a review can see what was skipped on purpose.
  • Generate - POST /v1/courses/:id/generate renders one module into an ordinary video, which then works with export, translate and everything else.

Each step is async and returns a jobId. Only one step runs per module at a time - a second request gets 409.

New scopes: courses:read, courses:write.

v1.12.0 - Brand Kit

The settings that keep generated output on-brand are now readable and writable by API. They were always applied - nothing could inspect or change them, so an API-only integration was stuck with whatever the dashboard had.

  • Brand Kit - GET|PATCH /v1/brand-kit: music, scenes, watermark, background, caption and article styling, default voice and language.
  • Pronunciations - how words should be said in narration.
  • Brand skills - reusable style guides, applied per video via scriptSkillId on analyze.
  • Glossary - brand terms and their translations, including CSV import with merge or replace. This feeds the translation pipeline, so it directly improves translation quality.

New scopes: brand_kit:read, brand_kit:write.

v1.11.0 - Phase 1 complete

  • Create a photo avatar - POST /v1/avatars, from a public image URL. Enterprise plan; new scope avatars:write.
  • Article styling - style on generate and fetch, returned as articleStyle so embedded HTML can be rendered on-brand. Presentation only; the wording is unchanged.
  • Cursor pagination on projects - now on all three collection endpoints.

API keys created in an admin or internal workspace now carry admin status. Previously only OAuth tokens did, so an admin's API key was metered and throttled like any customer's.

v1.10.0 - The rest of the options

  • Voiceover: model, speed, stability.
  • Analyze: keyEvents, analysisModel, subtitleModel, autoZoom.
  • Export: reframe, slides, avatarSettings.
  • Get the article - GET /v1/videos/:id/article, in Markdown or HTML, without regenerating it.
  • Get one avatar - GET /v1/avatars/:id.
  • Delete a cloned voice - DELETE /v1/voices/:id. New scope voices:write.
  • WebVTT - download?type=vtt, generated from the subtitles, so it works without an export.
  • Cursor pagination on /v1/videos and /v1/jobs. page still works; cursor is what to use when walking a collection that's changing under you.

Not available through the API, with reasons: article PDF/DOCX export and auto-extracted screenshots (both need capabilities the API service doesn't carry), voice cloning (needs recorded consent), and voiceover loudness matching (only applies to single-clip regeneration).

v1.9.0 - Scripts, downloads, webhooks and idempotency

The last of the gaps that made the API awkward to build against.

Edit the script

  • Get and replace a video's timed lines - the text burned in as subtitles and spoken as narration. Fix a typo without re-analyzing.
  • Editing a line's text drops the narration generated from it, so an export can't say something the subtitles no longer show. voiceoverInvalidatedLines tells you how many lines were affected; untouched lines keep their audio.

Get your files

  • Download - GET /v1/videos/:id/download?type=… for the exported video, the source, the voiceover audio, the SRT, or the thumbnail. Returns a clear reason when the file isn't ready instead of a null field.

Manage webhooks

  • Create, update and delete webhooks through the API. Previously dashboard-only, so an integration couldn't provision its own delivery endpoint.
  • The signing secret is returned once, at creation. Re-enabling a failed webhook resets its failure count.

Retry safely

  • Idempotency - send Idempotency-Key on any POST and the request runs once, however many times it arrives. A duplicate export or tool run costs real money; this is the general fix.

More options

  • Voiceover gained sentencePauseSeconds and applyPronunciations (on by default, matching everywhere else in Vidocu).
  • Article gained language, instructions and format (markdown or html).

New scopes: webhooks:read, webhooks:write. subtitles:write now also covers script edits.


v1.8.0 - Look up voices, avatars and what things cost

Three reference endpoints, plus a machine-readable spec.

  • Voices - GET /v1/voices. voiceId was a required parameter with no way to discover a valid value, so callers copied one out of the dashboard. Your own cloned voices come first, marked custom: true.
  • AI Avatars - GET /v1/avatars. Searchable by name; your workspace's photo avatars always come first.
  • Credit costs - GET /v1/usage/credits. What each operation costs alongside your balance, so you can price a job before starting it.
  • OpenAPI spec - openapi.json, generated from the server's own validation schemas rather than written by hand, so it can't drift from what the API accepts.

New scopes: voices:read, avatars:read. Available through MCP as list_voices, list_avatars and get_credit_costs.


v1.7.1 - Tool runs are charged on completion

Tool runs started through the API were checked against your balance at dispatch and then never deducted - the run happened, the balance didn't move. They're now charged when the run succeeds, using the quantity the renderer reports rather than the estimate in your request.

  • A failed run costs nothing. Charging happens on success, not dispatch.
  • The billed quantity is the real one - actual output duration, actual slide count.
  • Grandfathered minutes plans are unaffected - tool runs remain uncharged there.

If you've been running tools through the API, expect balance.used in GET /v1/usage to start moving where it previously stood still.


v1.7.0 - Control how videos are analyzed and rendered

Export accepted one field, language. Everything else came from the stored video and your Brand Kit, so "render this one vertical without a watermark" wasn't expressible.

It now takes per-request overrides: ratio, watermark, captions, music, openingSceneUrl, closingSceneUrl, zooms and elements. Precedence is request > video > Brand Kit, and the overrides apply to that render only - nothing stored changes. Pass false to drop a whole track: {"watermark": false, "music": false}.

Analyze gained the options the product has had all along: contentStyle (how-to, sop, promotional, training, announcement), productName, scriptSource (analyze the footage, reuse the transcript, keep the original audio, or supply your own script), customScript, scriptSkillId for a Brand Kit style guide, and forceRefresh.

Both are available through the MCP server on export_video and analyze_video.


v1.6.0 - Manage videos, find jobs, look up languages

Four endpoints that were missing rather than broken.

  • Update Video - PATCH /v1/videos/:id. Rename, move between projects, or adjust the context used when generating content. A locked video can still be moved; anything else returns 423.
  • Delete Video - DELETE /v1/videos/:id. Removes the video and its stored files. Until now you could create videos through the API and never remove them. Locked videos are refused.
  • List Jobs - GET /v1/jobs. Recent jobs newest first, filterable by status and type, for when you've lost a jobId.
  • Languages - GET /v1/languages. All 54 supported languages with the exact codes analyze, translate, voiceover and subtitleLanguage expect, so you don't have to guess one and get a 400.

All four are available through the MCP server as update_video, delete_video, list_jobs and list_languages.


v1.5.0 - Locks, roles, and honest tool pricing

Four corrections to existing endpoints. Nothing was renamed or removed.

Locked content is now respected

A locked video's content is frozen while it moves through an approval cycle. The API previously ignored locks entirely: analysis, voiceover, translation and article generation would all overwrite a locked package, and DELETE /v1/projects/:id?cascade=true would delete locked videos along with their stored files.

  • Those four operations now return 423 Locked
  • A cascading project delete is refused if the project holds any locked video
  • GET /v1/videos and GET /v1/videos/:id return locked and lock
  • Exporting a locked video still works - rendering from frozen content is the point

Workspace roles apply to OAuth tokens

Scopes describe what an integration asked for; the workspace role behind the token describes what that person may do. Both are now enforced, so a token minted by a viewer can hold videos:write and still be refused with 403 insufficient_role.

API keys are unchanged - a key authenticates as a workspace, not a user, and keeps full workspace permissions.

Tools bill at their real rate

Every tool executed through the API used to bill the same flat per-run rate regardless of what it did. Each tool now bills against its own entry: per minute, per slide, or per run. Most are unchanged at 1 credit per minute; the expensive ones are now charged properly (AI avatar generation is 150 credits per minute). See Execute Tool.

Presentation tools (PDF, PPTX, Keynote, Google Slides to video) now execute correctly through the API; previously they were dispatched to the wrong backend.

AI avatar generation and subtitle burning now work through the API. Both render inside Vidocu rather than on the tool backend, so they were previously unreachable. They behave like any other tool - 202 with a jobId - except they don't fire a tool.completed webhook, so poll GET /v1/jobs/:id for those two. List Tools reports apiSupported for every tool; it's false only when a tool genuinely can't be reached.

Usage reports your actual unit

GET /v1/usage now returns billingModel and a unit-tagged balance block. Most workspaces are billed in credits, which the old videoMinutes field labelled as minutes. That field is kept with the same values and is now deprecated.


v1.4.1 - API keys on every plan

The REST API is no longer gated to Business. API keys now work on every Vidocu plan, including Free - same as the MCP integration. Your plan only determines your monthly allowance and max video duration per request. See Plans & Limits.


v1.4.0 - API access included with Business

The standalone API plans (Starter, Growth, Scale) are gone. API access is now part of your Vidocu plan.

  • REST API (API keys) is available on the Business plan and above. There's no separate API subscription to buy.
  • The Claude / MCP integration works on any plan when you connect with OAuth.
  • One shared meter. API usage now draws from the same monthly video-minute allowance as the app, instead of a separate API quota.
  • Fixed rate limit of 60 requests/minute for every plan.
  • No more per-feature gating. Translation, voiceover, and /process are available to every API caller. Within /process, only analysis and translation consume minutes; voiceover, export, and help articles are free.

See Plans & Limits for the full breakdown.


v1.3.0 — MCP Server

Connect Vidocu to AI assistants like Claude via the Model Context Protocol.

  • MCP server at mcp.vidocu.ai — 15 tools covering all API operations
  • Streamable HTTP transport, stateless, works with Claude Desktop and other MCP clients
  • Authenticate with your existing API key via X-Vidocu-Api-Key header

v1.2.0 — One-Shot Processing

Process a video end-to-end with a single API call. Upload a video URL and specify which operations to run — the API chains them automatically and reports progress via job polling or webhooks.

New endpoint

  • Process videoPOST /v1/videos/process — upload + analyze + optionally generate voiceover, help article, export, and translations in one request (Business+)

New webhook events

  • process.completed — all pipeline steps finished successfully
  • process.failed — a step in the pipeline failed

Improvements

  • Analysis results (subtitles, key events, status) are now persisted to the video document immediately after analysis completes, so GET /v1/videos/:id/subtitles returns results without requiring a separate save step

v1.1.0 — Tools API

Execute free tools (video trimmer, subtitle translator, transcript extractor, etc.) programmatically through the API.

New endpoints

  • List toolsGET /v1/tools — discover all available tools and their parameter schemas
  • Get toolGET /v1/tools/:type — get a single tool's full definition
  • Execute toolPOST /v1/tools/:type/execute — run a tool and get a job ID

Improvements

  • tool.completed and tool.failed webhook payloads now include toolType and result fields
  • Job polling (GET /v1/jobs/:id) now supports tool jobs
  • Usage tracking includes toolExecutions counter

v1.0.0 — Initial release

The Vidocu API v1 is now available.

Endpoints

  • UploadPOST /v1/videos/upload
  • List videosGET /v1/videos
  • Get videoGET /v1/videos/:id
  • AnalyzePOST /v1/videos/:id/analyze
  • ExportPOST /v1/videos/:id/export
  • TranslatePOST /v1/videos/:id/translate (Growth+)
  • SubtitlesGET /v1/videos/:id/subtitles
  • VoiceoverPOST /v1/videos/:id/voiceover (Growth+)
  • ArticlePOST /v1/videos/:id/article
  • JobsGET /v1/jobs/:id
  • UsageGET /v1/usage

Features

  • API key authentication (vdo_live_ format)
  • Per-key rate limiting with response headers
  • Webhook delivery with HMAC SHA-256 signatures
  • 4 plans: Starter, Growth, Scale, Enterprise
  • JSON and SRT subtitle formats