Keyframe Labs Generations API
The Generations API from Keyframe Labs — 3 operation(s) for generations.
The Generations API from Keyframe Labs — 3 operation(s) for generations.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/keyframe-labs:keyframe-labs-generations-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Sessions Generations API
version: 1.2.0
servers:
- url: https://api.keyframelabs.com/v1
tags:
- name: Generations
paths:
/uploads:
post:
tags:
- Generations
operationId: createUpload
security:
- bearerAuth: []
summary: Create audio upload
description: 'Returns a signed URL to PUT one audio file to. Takes no request body. Upload the raw bytes with no required headers, then pass the returned `id` as `audio_file_id`.
One upload can back several generations -- the same audio rendered as mp4 and webm, or re-run with a different emotion timeline -- without re-sending it.'
responses:
'201':
description: Upload URL issued
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUploadResponse'
'401':
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: Invalid API Key
param: null
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
internal_error:
value:
error:
code: internal_error
message: Internal server error
param: null
/generations:
post:
tags:
- Generations
operationId: createGeneration
security:
- bearerAuth: []
summary: Create generation
description: 'Queues a batch render and returns immediately with a `queued` job. Poll it, or supply a `webhook`.
The uploaded audio is inspected before the job is created: an unreadable file, a file containing a video stream, an unsupported codec or one longer than the limit is rejected with 400 and nothing is queued. `duration_seconds` in the response is measured, not declared.'
parameters:
- name: Idempotency-Key
in: header
required: false
schema:
type: string
description: Re-sending the same key returns the original job instead of queueing a second one. Scoped to your organisation.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateGenerationRequest'
responses:
'201':
description: Generation queued
content:
application/json:
schema:
$ref: '#/components/schemas/Generation'
'400':
description: Invalid request or unusable audio
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: file contains a video stream; upload audio only
param: audio_file_id
'401':
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: Invalid API Key
param: null
'402':
description: Billing issue
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
payment_required:
value:
error:
code: payment_required
message: No active subscription found. Please set up billing.
param: null
'403':
description: Model not allowed for plan
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
model_not_allowed:
value:
error:
code: model_not_allowed
message: Plan 'free' does not support model persona-1.5
param: model
'429':
description: Too much work already queued
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
queue_limit_exceeded:
value:
error:
code: queue_limit_exceeded
message: You already have 50 generations queued or running. Wait for some to finish before submitting more.
param: null
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
internal_error:
value:
error:
code: internal_error
message: Internal server error
param: null
get:
tags:
- Generations
operationId: listGenerations
security:
- bearerAuth: []
summary: List generations
description: Newest first. Cursor-paginated rather than offset-paginated, because the queue changes while you page through it and an offset would skip or repeat rows.
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: after
in: query
required: false
schema:
type: string
description: '`next_cursor` from the previous page.'
- name: status
in: query
required: false
schema:
type: string
enum:
- queued
- running
- done
- failed
responses:
'200':
description: Generations returned
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationList'
'400':
description: Malformed cursor
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: malformed cursor
param: after
'401':
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: Invalid API Key
param: null
/generations/{generation_id}:
get:
tags:
- Generations
operationId: getGeneration
security:
- bearerAuth: []
summary: Get generation
description: Returns the job, with a freshly signed `output_url` when it is done. The link is valid for 30 minutes and is not stored -- read the generation again to get another.
parameters:
- name: generation_id
in: path
required: true
schema:
type: string
description: Generation identifier
responses:
'200':
description: Generation returned
content:
application/json:
schema:
$ref: '#/components/schemas/Generation'
'401':
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
invalid_request:
value:
error:
code: invalid_request
message: Invalid API Key
param: null
'404':
description: No such generation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiErrorResponse'
examples:
generation_not_found:
value:
error:
code: generation_not_found
message: no generation with id gen_123
param: null
components:
schemas:
CreateUploadResponse:
description: 'A signed URL for one audio upload. Takes no request body: anything you could declare here would be unverified, so size and content are checked against the stored object when the generation is created.'
type: object
required:
- id
- object
- upload_url
- method
- expires_at
properties:
id:
type: string
description: Pass as `audio_file_id` when creating a generation.
example: 9f2c1e7a4b
object:
type: string
enum:
- upload
upload_url:
type: string
format: uri
description: PUT the raw audio bytes here. No headers are required.
method:
type: string
enum:
- PUT
expires_at:
type: string
format: date-time
description: After this the URL stops working, but the id stays valid for an upload already completed.
GenerationList:
type: object
required:
- object
- data
- has_more
properties:
object:
type: string
enum:
- list
data:
type: array
items:
$ref: '#/components/schemas/Generation'
has_more:
type: boolean
next_cursor:
type:
- string
- 'null'
description: Pass as `after` for the next page. Opaque.
ApiErrorResponse:
description: 'Structured error envelope used by the Generations and Uploads endpoints. A superset of the `detail` shape the older endpoints return: `code` is stable and safe to branch on, `param` names the offending field when one is identifiable.'
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
enum:
- model_not_allowed
- persona_not_found
- invalid_request
- payment_required
- queue_limit_exceeded
- generation_not_found
- internal_error
message:
type: string
param:
type:
- string
- 'null'
description: Request field that caused the error, when known.
Generation:
type: object
required:
- id
- object
- model
- persona_id
- status
- output_format
- duration_seconds
- credits_estimated
- created_at
properties:
id:
type: string
object:
type: string
enum:
- generation
model:
type: string
persona_id:
type: string
status:
type: string
enum:
- queued
- running
- done
- failed
description: Terminal states are `done` and `failed`. There is no cancelled state.
output_format:
type: string
enum:
- mp4
- webm
- mov
duration_seconds:
type: number
description: Measured from the uploaded audio, not supplied by the caller.
credits_estimated:
type: number
description: Quote at submit. The charge is based on what is actually rendered.
credits_charged:
type:
- number
- 'null'
description: Set on `done`.
output_url:
type:
- string
- 'null'
format: uri
description: Signed download link, valid 30 minutes. Re-read the generation for a fresh one; it is not stored.
error:
type:
- string
- 'null'
description: Set on `failed`.
metadata:
type:
- object
- 'null'
additionalProperties:
type: string
created_at:
type: string
format: date-time
completed_at:
type:
- string
- 'null'
format: date-time
WebhookConfig:
type: object
required:
- url
properties:
url:
type: string
format: uri
description: HTTPS endpoint that receives lifecycle events.
secret:
type: string
minLength: 16
maxLength: 256
description: 'Signs deliveries as `KFL-Signature: t=<unix>,v1=<hmac-sha256>` over `"{t}.{body}"`. Generated if omitted.'
EmotionKeyframe:
type: object
required:
- at
- name
properties:
at:
type: number
minimum: 0
description: Seconds from the start of the clip. Floored to the model's one-second inference window.
name:
type: string
example: happy
CreateGenerationRequest:
description: Queue a batch video generation. The audio must already be uploaded via POST /uploads.
type: object
additionalProperties: false
required:
- model
- persona_id
- audio_file_id
properties:
model:
type: string
example: persona-1.5
description: Must appear in your plan's allowed models.
persona_id:
type: string
description: ID of avatar to use
audio_file_id:
type: string
description: '`id` returned by POST /uploads, after the audio has been PUT to the signed URL.'
output_format:
type: string
enum:
- mp4
- webm
- mov
default: mp4
emotion:
description: One emotion for the whole clip, or a timeline. Resolution is one second.
oneOf:
- title: Single emotion
type: string
example: happy
- title: Timeline
type: array
items:
$ref: '#/components/schemas/EmotionKeyframe'
webhook:
$ref: '#/components/schemas/WebhookConfig'
metadata:
type: object
additionalProperties:
type: string
maxProperties: 16
description: Returned unchanged on reads and webhooks; never interpreted.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
x-provenance:
method: harvested
publisher: Keyframe Labs
source: https://docs.keyframelabs.com/api-reference/v1/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)