The mint API lets your own systems (for example a learning platform) read the catalogs, briefing templates and categories of your company in mint, create categories and order films: POST /films creates a film from a briefing (title, narration text, template or settings); mint can then plan it and produce it automatically up to the storyboard or the finished film. Read your films with GET /films and GET /films/{id} and cancel them with POST /films/{id}/cancel until the storyboard is ready. Follow changes in the event feed GET /events and download approved films with GET /films/{id}/file (and their subtitles). It is a server-to-server API: browsers on other sites cannot call it (no CORS).
Kurz auf Deutsch. Mit der mint API binden Sie mint an Ihre eigenen Systeme an, zum Beispiel an eine Lernplattform. Sie bestellen Filme aus einem Briefing, verfolgen den Fortschritt, geben Feedback zum Storyboard und laden freigegebene Filme herunter. Die Freigabe eines Films bleibt immer bei einer Person in mint. Die Referenz ist auf Englisch, wie die API selbst. Der schnellste Einstieg ist der Quickstart; Zugänge und Schlüssel legen Admins Ihrer Firma in mint unter Einstellungen → API-Zugänge an.
Base URL
https://api.cream-ai.de/api/v1. All paths in this document are relative to it. Requests and responses use JSON (UTF-8) unless an endpoint says otherwise, for example file downloads and uploads. All times are UTC in ISO 8601.
How a film flows through the API
- Read your catalogs once: templates, styles, brands, voices and categories.
- Order a film with
POST /films. mint plans and produces it up to the storyboard (or the film). - Follow its state with the event feed or
GET /films/{id}/progress. - Optionally review it: a storyboard preview, feedback on scenes, comments on the finished film.
- A person approves the film in mint. Then download it with
GET /films/{id}/file.
https://api.cream-ai.de/api/v1curl https://api.cream-ai.de/api/v1/me \
-H "Authorization: Bearer $MINT_API_KEY"From zero to a downloaded film in six steps. You need an API key with the scopes catalog:read, films:write, events:read and files:read.
1. Create an API key
A company admin creates an API access in mint under Settings → API access, chooses the scopes and copies the key. The key is shown only once. Keep it on your server, for example in an environment variable:
export MINT_API_KEY="mint_sk_live_…"
2. Check the key
GET /me shows the access, its company, scopes and limits. A 401 means the key is wrong, revoked or expired.
3. Pick a template
GET /templates lists the briefing templates of your company. A template fixes the style, brand, voice and further settings, so the order itself stays short. Use its key as template.
4. Order the film
POST /films with a title, the narration text, the e-mail address of the responsible mint user and your own video_key + version. With automation: "storyboard" (the default) mint plans and produces the storyboard and then waits for review. Sending the same order again returns the same film, so retries are safe.
5. Follow the progress
Poll the event feed, for example every few minutes, or read GET /films/{id}/progress while a person is watching. film.storyboard_ready tells you that the storyboard can be reviewed in mint; film.approved that the film is final.
6. Download the approved film
GET /films/{id}/file returns the MP4. Its ETag is the SHA-256 of the file; compare it after the download.
curl https://api.cream-ai.de/api/v1/me \
-H "Authorization: Bearer $MINT_API_KEY"curl -X POST https://api.cream-ai.de/api/v1/films \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Lesson 3: Market segmentation",
"narration_text": "Not every customer wants the same thing. …",
"user_email": "anna.schmidt@example.edu",
"template": "lesson-standard",
"video_key": "MKT101-lesson-03",
"version": "1.0"
}'curl "https://api.cream-ai.de/api/v1/events?after=0&types=film.storyboard_ready,film.approved" \
-H "Authorization: Bearer $MINT_API_KEY"curl https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file \
-H "Authorization: Bearer $MINT_API_KEY" \
-o film.mp4 -D headers.txt
shasum -a 256 film.mp4 # compare with the ETagCompany admins create an API access in mint under Settings → API access. Each access has its own scopes and keys. A key is shown only once, right after it was created. Send it in the Authorization header:
curl -H "Authorization: Bearer mint_sk_live_…" https://api.cream-ai.de/api/v1/me
Keys in query strings are never accepted. GET /me shows the access, its company, scopes, key and limits. Revoking a key or changing scopes in mint takes effect immediately.
The mint API must be enabled for your company by mint. Until then, or after it was disabled, every request with a key of this company returns 403 api_not_enabled; your accesses and keys are kept and work again once the API is enabled.
Keep keys secret
- Use the key only from your server. The API does not allow calls from browsers on other sites (no CORS).
- Do not put keys into source code, URLs, tickets or logs. Store them in a secret store or an environment variable.
- Each access can have up to two valid keys at the same time, so you can rotate a key without downtime: create the new key, deploy it, then revoke the old one.
- An access can be limited to IP addresses and can expire.
GET /meshowsexpires_at.
curl https://api.cream-ai.de/api/v1/me \
-H "Authorization: Bearer $MINT_API_KEY"{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"request_id": "req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c"
}
}Every API access has its own scopes. A request with a key that lacks a scope returns 403 forbidden_scope; details.required_scopes names what is missing. Writing scopes include reading the same area.
| Scope | Allows |
|---|---|
catalog:read | Read approved styles, brands and voices and active briefing templates of this company as compact lists. |
categories:read | Read the category tree of this company, also by external key. |
categories:write | Create and rename categories and subcategories and link them to an external key. Includes categories:read. |
films:read | Read films, status and production progress. |
films:write | Create films from a briefing, have them produced automatically up to the storyboard or the film, and cancel them. Includes films:read. |
files:read | Download approved film files and subtitles. |
previews:read | Download the storyboard version of a film as MP4, also before approval. |
previews:write | Have a storyboard preview of a film created as MP4. Each new preview costs credits. Includes previews:read. |
events:read | Read the continuous event feed of this company with a cursor (film objects in the feed only together with films:read). |
uploads:write | Upload images and videos to use them in feedback and comments. |
feedback:write | Send, cancel and retry feedback on scenes, and read and add comments on the finished film. Feedback changes the scenes like a message in the chat and may cost credits. |
films:revise | Have open comments applied to the film; mint creates a new revision of the film from them (costs credits). Includes films:read. |
GET /me and GET /openapi.json need no scope. More scopes follow with later versions.
Endpoints by scope
{
"error": {
"code": "forbidden_scope",
"message": "This API key does not have the scope films:write.",
"request_id": "req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c",
"details": { "required_scopes": ["films:write"] }
}
}mint uses HTTP status codes: 2xx success, 4xx a problem with the request, 5xx a problem on the mint side.
All errors share one format:
{ "error": { "code": "forbidden_scope", "message": "…", "request_id": "req_…", "field": "…", "details": {} } }
code is stable and machine readable, message is for humans and may change, field names the affected input. Every response carries an X-Request-Id header; please quote it when you contact support.
Handling errors
- Branch on
error.code, never onmessage. 429and503are temporary: wait forRetry-Afterseconds and retry the same request with the sameIdempotency-Key.409codes withRetry-After(for examplefilm_busy,idempotency_in_progress) are temporary as well.- New codes may be added within v1. Treat an unknown
4xxcode likeinvalid_requestand an unknown5xxcode likeinternal.
Error codes
{
"error": {
"code": "version_conflict",
"message": "Version 1.0 of this video_key already exists with other content.",
"request_id": "req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c",
"field": "version",
"details": { "film_id": "k7m2xq9v4t8n1b5r3c6d0wza" }
}
}HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7cNetworks fail. With an Idempotency-Key you can safely send a writing request again: mint runs it at most once and returns the stored response for every repeat.
Writing POST requests require an Idempotency-Key header (1–128 visible ASCII characters, for example a UUID); PATCH accepts it optionally. POST /films accepts it optionally when the body has a video_key (the version identity then protects against duplicates); without video_key it is required (400 idempotency_key_required). POST /films/{id}/cancel accepts it optionally. Repeating a request with the same key and the same body returns the stored response with Idempotent-Replayed: true and changes nothing. This also applies to error responses (400, 404, 409): their body is replayed unchanged, so error.request_id names the original request, while X-Request-Id names the current one. Temporary rejections are not stored (409 feedback_busy, 409 film_busy, 409 preview_in_progress, 409 storyboard_not_ready, 402 insufficient_credits, 409 feedback_queue_full): a retry with the same key runs again once the reason is gone. The same key with a different request returns 422 idempotency_mismatch; while the first request is still running you get 409 idempotency_in_progress with Retry-After. Keys are kept per API access for 24 hours by default; the operator of a mint server can set 1–72 hours. GET /me shows the current value in idempotency_key_ttl_hours.
Good practice
- Create a new random key (for example a UUID v4) for every new action, and reuse it only for retries of that action.
- Store the key together with your own job, so a retry after a crash uses the same key.
- For films, prefer
video_key+version(see Film versions): they protect against duplicates for as long as the film exists, not only for 24 hours.
curl -X POST https://api.cream-ai.de/api/v1/categories \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: 9b1d3c5e-7f2a-4c6e-8a0b-2d4f6a8c0e1b" \
-H "Content-Type: application/json" \
-d '{ "name": "Marketing", "external_key": "MKT" }'HTTP/1.1 201 Created
Idempotent-Replayed: true
X-Request-Id: req_0c3e5a7b9d1f2e4a6c8b0d2f4e6a8c1bYour system usually has its own id for a video, for example a lesson in a course. Send it as video_key, together with a version. mint then treats video_key + version as the identity of the film within your company.
- Every film is ordered on behalf of a person:
user_emailmust belong to an active member of your company. This person is the owner of the film in mint and gets the e-mail "storyboard ready", together with the admins of your company. automationisstoryboard(default),filmornone. With automation, mint needs a fixed style (from the template orsettings.style_id) and enough credits for the estimated film (402 insufficient_creditsotherwise). The operator of a mint server can switch the automation off; films are then created without it and carrynotice.codeautomation_disabled.- Credits are always taken from the credits of your company, never from a team budget. Each booking of an API film is marked "API" with the name of the access in the usage list of your company.
video_key+versionidentify a film version. The same order again returns the existing film (200, nothing is booked); a different order for an existing version returns409 version_conflict.- Film status:
briefing,in_production,storyboard_ready,film_ready,approvedorcancelled. Only the approved original version is the film; format and language versions are not part of v1.
Versions in practice
| You send | mint does |
|---|---|
MKT101-lesson-03 1.0, first time | creates the film (201) |
| the same order again | returns the existing film (200), books nothing |
1.0 again, but with a changed text | 409 version_conflict with details.film_id |
1.1 with a changed text | creates a new film that takes over style, brand, voice and category of 1.0 |
Versions are major.minor or major.minor.patch without leading zeros. Use GET /films?video_key=… to list all versions of a video; is_latest_approved_version marks the newest approved one.
{
"title": "Lesson 3: Market segmentation",
"narration_text": "Not every customer wants the same thing. …",
"user_email": "anna.schmidt@example.edu",
"video_key": "MKT101-lesson-03",
"version": "1.1"
}curl "https://api.cream-ai.de/api/v1/films?video_key=MKT101-lesson-03" \
-H "Authorization: Bearer $MINT_API_KEY"Lists return { "object": "list", "data": [], "has_more": false, "next_cursor": null }. Pass next_cursor as cursor to get the next page; limit is 1–100 (default 50). Cursors are opaque and only valid for the same query and filters.
The list object
listPass as cursor to get the next page; null on the last page.
The event feed is the exception: it pages with after and next_after instead of a cursor, see Event feed.
let cursor;
do {
const url = new URL("https://api.cream-ai.de/api/v1/films");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.MINT_API_KEY}` },
});
const page = await res.json();
for (const film of page.data) console.log(film.id, film.status);
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);params = {"limit": 100}
while True:
page = requests.get(f"{BASE}/films", headers=HEADERS, params=params).json()
for film in page["data"]:
print(film["id"], film["status"])
if not page["has_more"]:
break
params["cursor"] = page["next_cursor"]mint v1 has no webhooks. Instead, every company has an ordered event feed: you ask for everything after the last event you processed. This works behind firewalls, needs no public endpoint on your side and never loses an event while your system is down.
A person approves a film in mint; only then can it be downloaded. The key needs films:read, events:read and files:read. Downloads and the feed are free of credits.
GET /events?limit=1: notelatest_seqas H.GET /films?status=approved(all pages): download each film fromfile_urland compare the SHA-256 of the bytes with theETag.- From then on, for example once a day:
GET /events?after=H&types=film.approved,film.approval_revoked,film.deleted, process the events, storenext_afteras the new H, repeat whilehas_more. 410 cursor_expiredor400 invalid_cursor: start again with step 1.
A film can be downloaded as long as its approval is active: after a revocation the download returns 404 not_approved; after a new approval only the new revision is available. Films that change between step 1 and 2 come twice; that is harmless because the SHA-256 identifies the file.
Event types
film.createdfilm.status_changedfilm.storyboard_readyfilm.approvedfilm.approval_revokedfilm.cancelledfilm.deletedfilm.progressfeedback.updatedstoryboard.preview_readyoperation.completed
New types may be added within v1; ignore types you do not know. Events are kept for 180 days.
Rules for a robust consumer
- Store
next_afteronly after the page was processed. If you crash in between, you read the page again. - Events can come twice (at least once delivery). Use the event
idto skip duplicates. datais a snapshot at the time of the event;film(withfilms:read) is the current state.- Poll every few minutes. There is no need to poll faster than once a minute.
let after = await loadCursor(); // e.g. from your database, start with "0"
for (;;) {
const url = new URL("https://api.cream-ai.de/api/v1/events");
url.searchParams.set("after", after);
url.searchParams.set("types", "film.approved,film.approval_revoked,film.deleted");
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.MINT_API_KEY}` },
});
if (res.status === 410 || res.status === 400) {
after = await resync(); // step 1 and 2 above
continue;
}
const page = await res.json();
for (const event of page.data) await handle(event);
after = String(page.next_after);
await saveCursor(after);
if (!page.has_more) break;
}Approved films are downloaded with GET /films/{id}/file, their subtitles with GET /films/{id}/subtitles.srt. Storyboard previews work the same way with GET /films/{id}/storyboard-preview/file. Downloads are free of credits.
ETag = SHA-256
Every file comes with a strong ETag: the SHA-256 of the file in quotes. For films it equals approval.sha256 of the film. Compute the SHA-256 of the bytes you received and compare. If an event is older than the current approval, the ETag counts.
Resume a download
Send Range: bytes=<from>- together with If-Range: <ETag>. If the file is unchanged, mint answers 206 with the rest; if a new approval exists in the meantime, 200 with the whole new file. One range per request is supported.
Skip unchanged files
Send If-None-Match: <ETag>. mint answers 304 without a body if you already have the current file. HEAD returns the headers only.
When a download is not possible
| Response | Meaning |
|---|---|
404 not_approved | The film has no active approval (never approved, or revoked). |
404 subtitles_not_available | The approval has no subtitles. |
409 file_unavailable | The file is temporarily not available. Retry later. |
429 rate_limited | Too many downloads at the same time (details.reason parallel_downloads). Wait for Retry-After. |
503 | mint is briefly checking the file. Wait for Retry-After. |
curl https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file \
-H "Authorization: Bearer $MINT_API_KEY" \
-D headers.txt -o film.mp4
grep -i etag headers.txt
shasum -a 256 film.mp4curl https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Range: bytes=33554432-" \
-H 'If-Range: "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"' \
-o film.partLong-running requests answer 202 Accepted with a Location header that points to /api/v1/operations/{id} and an Operation object. Poll it until status is succeeded or failed. Operation types are storyboard.preview and film.comments_apply; more may follow within v1.
The operation also reports its end in the event feed (operation.completed), so you can follow it there instead of polling. See Operations for the object and the endpoint.
HTTP/1.1 202 Accepted
Location: /api/v1/operations/op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6acurl https://api.cream-ai.de/api/v1/operations/op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a \
-H "Authorization: Bearer $MINT_API_KEY"Requests are limited per key and per company; GET /me shows the limits in rate_limits. Exceeding a limit returns 429 rate_limited with Retry-After (seconds). JSON request bodies may be at most 256 KB and nested at most 32 levels deep (otherwise 400 invalid_request with field body). An error before the body was read closes the connection (Connection: close). Catalog lists (styles, brands, voices) and the category list may show changes with a delay of up to 30 seconds.
Fixed limits
| What | Limit |
|---|---|
| JSON request body | 256 KB, nested at most 32 levels |
narration_text | 18,000 characters |
Page size (limit) | 1–100, default 50 |
| Uploads | images up to 25 MB, videos up to 200 MB, kept 7 days after the last use |
| Idempotency keys | kept 24 hours by default (GET /me shows the current value) |
| Events | kept 180 days |
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Retry after 12 seconds.",
"request_id": "req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c"
}
}Within v1 there are only additions: new endpoints, new optional request fields, new response fields and new enum values. Ignore fields you do not know. Breaking changes come with a new version (/api/v2).
The version is part of the path (/api/v1). GET /me shows it in api_version. The complete contract is available as OpenAPI 3.1 at GET /openapi.json, for example to generate a client.
curl https://api.cream-ai.de/api/v1/openapi.json -o mint-api-v1.openapi.jsonAn API access (service account) belongs to one company. It has scopes, up to two keys and optional limits such as an expiry date or allowed IP addresses. Company admins manage accesses in mint under Settings → API access.
Attributes
api_clientShow child attributes
Company id in mint.
Scopes granted to this access (without implied scopes).
Expiry of this API access, set by a company admin in mint. Afterwards every key of the access is rejected with 401. null if the access does not expire.
Show child attributes
Visible part of the key.
End of the grace period of this key after a rotation; null if the key itself has no end. The access can still expire earlier, see expires_at of the access.
Show child attributes
Read requests per minute for this key.
Write requests per minute for this key.
Read requests per minute for all keys of the company.
Write requests per minute for all keys of the company.
How long an Idempotency-Key of this access is kept, in hours (default 24).
v1{
"object": "api_client",
"id": "0f6c2a9e-4b7d-4e1a-8c3f-5d2b9e7a1c64",
"name": "Learning platform",
"organization": {
"id": "org_4821",
"name": "Northwind University"
},
"scopes": [
"catalog:read",
"categories:write",
"films:write",
"files:read",
"events:read"
],
"expires_at": null,
"key": {
"id": "8e3b1d7a-2c5f-4a9e-b6d0-1f4c8a2e7b53",
"prefix": "mint_sk_live_3fa9c2e71b",
"expires_at": null
},
"rate_limits": {
"read_per_minute": 300,
"write_per_minute": 60,
"organization_read_per_minute": 1200,
"organization_write_per_minute": 240
},
"idempotency_key_ttl_hours": 24,
"api_version": "v1"
}Returns the API access (service account) the key belongs to, its company, scopes, key and limits. Needs a valid key, but no scope.
Returns
The API access of this key. Returns the API access object.
Errors 401 · 403 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/me" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/me", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/me",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "api_client",
"id": "0f6c2a9e-4b7d-4e1a-8c3f-5d2b9e7a1c64",
"name": "Learning platform",
"organization": {
"id": "org_4821",
"name": "Northwind University"
},
"scopes": [
"catalog:read",
"categories:write",
"films:write",
"files:read",
"events:read"
],
"expires_at": null,
"key": {
"id": "8e3b1d7a-2c5f-4a9e-b6d0-1f4c8a2e7b53",
"prefix": "mint_sk_live_3fa9c2e71b",
"expires_at": null
},
"rate_limits": {
"read_per_minute": 300,
"write_per_minute": 60,
"organization_read_per_minute": 1200,
"organization_write_per_minute": 240
},
"idempotency_key_ttl_hours": 24,
"api_version": "v1"
}Returns this document. Needs no key; responses may be cached for 5 minutes.
Returns
The OpenAPI document of the mint API v1.
Errors 429 · 500 · 503
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/openapi.json"const res = await fetch("https://api.cream-ai.de/api/v1/openapi.json");
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/openapi.json",
)
data = res.json(){
"openapi": "3.1.0",
"info": {
"title": "mint API",
"version": "1.0.0",
"description": "…"
},
"paths": {
"…": {}
}
}A film is ordered from a briefing: a title, the narration text and the mint user who is responsible for it. mint plans and produces it automatically up to the storyboard (automation: "storyboard") or up to the film ("film"). People review and approve the film in mint; the API never approves a film.
Status. briefing → in_production → storyboard_ready → film_ready → approved, or cancelled. stage shows the detailed stage as in the mint project list, attention_required and notice tell you when a person needs to act in mint.
Only films ordered through the API are visible to the API. Credits are always taken from your company.
A film ordered through the API. source is currently always api; app is reserved for projects created in mint, which v1 does not return yet.
Attributes
filmId of the film in mint.
Title as it is in mint now (people can change it there).
briefing: created in mint, nothing is running (for example with automation: none). in_production: mint is planning or producing the storyboard (or the film). storyboard_ready: the storyboard is ready for review in mint. With automation: storyboard the film stops here until a person continues in mint. film_ready: the film is rendered and waits for approval by a person in mint. approved: a person approved the film in mint. cancelled: the film was cancelled. New values may be added within v1.
Detailed stage as shown in the mint project list, or null if unknown. New values may be added within v1.
briefing style voice ready_to_plan planning storyboard_in_progress storyboard_review film_rendering film_ready approved paused error cancelledtrue if a person needs to act in mint (see notice).
Why a person needs to act in mint, or null. Codes: production_paused (“Production is paused in mint. Someone needs to resume it.”), production_failed (“Production failed in mint. Someone needs to check it.”), planning_failed (“Planning the storyboard failed in mint. Someone needs to check it.”), automation_failed (“The automatic storyboard could not be completed. Someone needs to continue in mint.”), insufficient_credits (“The company does not have enough credits. Someone needs to add credits and continue in mint.”), automation_disabled (“Automatic production is currently switched off. Someone needs to continue in mint.”).
Show child attributes
production_paused production_failed planning_failed automation_failed insufficient_credits automation_disabledShort English text (may change).
api: ordered through the API; app: reserved for projects created in mint (not returned in v1).
none: mint only creates the film with its briefing; people continue in mint. storyboard (default): mint plans and produces the storyboard automatically and stops at storyboard_ready for review. film: mint also renders the film without stopping at the storyboard (status film_ready). The film is always approved by a person in mint, never by the API.
Your key of the video, as sent.
Version of the video, canonical (1.0.0 is returned as 1.0).
Id of the film with the next lower version of the same video_key, or null.
true only if this film is approved and no higher, approved and not cancelled version of the same video_key exists.
Language of the film.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgKey of the template used when the film was created.
Effective settings of the film in mint. Values that are not set (or that mint cannot express in the API) are null.
Show child attributes
Aspect ratio.
16x9 9x16 1x1Id of the style (see GET /styles).
Revision of the style the film uses.
Effective brand (see GET /brands); null = no brand.
Voice of the narration (may also be a voice from the mint voice library); null = none set yet.
Name of the voice.
verbatim (default): narration_text is spoken word for word. smooth: mint polishes the language of narration_text and keeps its content. free: narration_text is the briefing; mint writes the narration freely (use target_duration_s for the length).
Pace of the film.
presenting lively kineticCreative freedom in percent.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds).
Category of the film in mint (see GET /categories), or null.
Show child attributes
categoryId of the category.
Key of the connected system, if set.
Top-level category of a subcategory; null for a top-level category.
Show child attributes
The mint user from user_email of the request (a Person with kind user). This user is responsible for the film in mint and is notified when the storyboard is ready. Personal data.
Show child attributes
Always user.
userE-mail address (lower case).
Name of the user at the time the film was created.
Your metadata, as sent. mint never uses it for the film. Key order is kept in POST /films (first response), GET /films and GET /films/{id}; a replayed response may order keys differently.
The active approval of the film (only the approved original version is the film), or null.
Show child attributes
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file, e.g. video/mp4.
true if subtitles were frozen with this approval (subtitles_url).
Who approved the film in mint (kind user, name and e-mail; email is null for approvals before 9 November 2026). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the cancellation (UTC), or null.
Creation time (UTC).
Last change (UTC).
Link to the film in mint (for people with access), or null.
Path of the approved file (GET /films/{id}/file, relative to the host of the API), or null without an active approval.
Path of the subtitles of the approval (GET /films/{id}/subtitles.srt), or null if the approval has none.
Rendered revisions of the film, newest last (only in GET /films/{id}, without file links).
Show child attributes
Number of the rendered revision.
rendering, ready or failed.
Start of the render (UTC).
End of the render (UTC), null while rendering.
Duration in seconds.
Resolution, e.g. 1920x1080.
{
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "approved",
"stage": "approved",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": {
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
}
},
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-11T14:30:00Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
"subtitles_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt",
"revisions": [
{
"revision": 1,
"status": "ready",
"created_at": "2026-11-10T08:21:37Z",
"finished_at": "2026-11-10T08:39:10Z",
"duration_s": 181.2,
"resolution": "1920x1080"
},
{
"revision": 2,
"status": "ready",
"created_at": "2026-11-11T13:50:00Z",
"finished_at": "2026-11-11T14:05:41Z",
"duration_s": 184.6,
"resolution": "1920x1080"
}
]
}Creates a film from a briefing in mint and, depending on automation, starts the automatic production. The film is always created with the settings of its template (template), the previous version and settings (in this order, settings wins).
Same order, same film. With video_key, the company-wide identity of a film is video_key + version. Sending the same order again (same title, narration_text, user_email, language, template, settings, category and automation) returns 200 with the existing film, even after the Idempotency-Key expired and with any key; nothing is created or charged again. metadata is not part of this comparison and is never changed by a repeated order. The same video_key and version with other content returns 409 version_conflict with details.film_id. While the same version is still being created you get 409 idempotency_in_progress with Retry-After; while a lower version of the same video_key is still being created, 409 previous_version_creating with Retry-After. A cancelled or deleted film frees its version: the same order then creates a new film. A setting that cannot be applied returns 400 invalid_request with field and details.code (style_not_available, style_not_approved, brand_not_available, voice_not_available, invalid_value, unsupported_version, unknown_setting, ai_music_not_enabled or not_applicable) and details.setting.
Idempotency-Key. Optional with video_key; without video_key it is required (400 idempotency_key_required). Errors that happen before mint reserved the order (for example 400 for a template that is not active) are not stored under the key, so you can correct the request and retry with the same key. A film without video_key that was deleted in mint returns 409 film_deleted for its key.
Automation. With automation other than none, a style must be set (by the template, the previous version or settings.style_id), otherwise 400 invalid_request (field settings.style_id). mint estimates the credits from the text length and the automation level; if the company does not have enough credits, the response is 402 insufficient_credits and nothing is created. Credits are always charged to the company, never to a team budget. If the automatic production cannot start, the film is still created (201) and notice tells what to do in mint. The request body may be at most 256 KB.
Headers
Optional unique key of this write request (1–128 visible ASCII characters). Retries with the same key return the stored response.
Request body
Title of the film (trimmed).
Text of the film (trimmed, 1–18,000 characters; longer texts return 400 narration_too_long). How it is used depends on settings.narration_mode. Tabs and line breaks are allowed, other control characters are not.
E-mail address of an active mint user of this company. The user becomes responsible for the film in mint and gets the e-mail when the storyboard is ready. Otherwise 400 user_not_in_company (field user_email). Compared without case.
Language of the film. Without it, the template, then the previous version, then de applies.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgKey of an active briefing template (GET /templates). Unknown or inactive keys return 400 template_not_found.
none: mint only creates the film with its briefing; people continue in mint. storyboard (default): mint plans and produces the storyboard automatically and stops at storyboard_ready for review. film: mint also renders the film without stopping at the storyboard (status film_ready). The film is always approved by a person in mint, never by the API.
storyboardOptional settings. They win over the template and the previous version; unknown keys return 400 invalid_request with field settings.<name>. The template may set further mint settings (for example music, depth or audience) that are not listed here.
Show child attributes
Aspect ratio (16x9, 9x16, 1x1; 16:9 etc. are accepted, too).
Id of a brand (GET /brands), or null for no brand. Omit it to keep the brand of the template, the previous version or mint’s automatic choice.
Voice id from GET /voices, or null for the automatic voice (the voice of the brand, if it has one).
verbatim (default): narration_text is spoken word for word. smooth: mint polishes the language of narration_text and keeps its content. free: narration_text is the briefing; mint writes the narration freely (use target_duration_s for the length).
verbatimPace of the film.
presenting lively kineticCreative freedom in percent.
0 25 40 65 100Target duration in seconds (1–900). mint keeps the length in steps of 6 seconds (0.1 minutes), so the value is rounded to the nearest 6 seconds (at least 6 seconds) and returned that way.
Category of the film. Allowed forms: { "id" }, { "external_key" }, { "path", "create"? } or { "path", "external_key", "create"? }. With path and external_key, mint first looks for the key; if it is missing and create is true, the path is created and the key is set on its last level. Path and key pointing to different categories return 400 invalid_request (field category). A category that does not exist returns 400 category_not_found. create: true also needs the scope categories:write (otherwise 403 forbidden_scope).
Show child attributes
Id of a category (GET /categories). Not combinable with other fields.
External key of a category (e.g. a module number).
Category names: [main] or [main, sub] (compared without case).
Create missing levels of path.
falseYour stable key of the video (case-sensitive). Together with version it identifies the film within the company.
Version of the video (major.minor or major.minor.patch, numbers without leading zeros). A higher version of the same video_key takes over style, brand, voice and category of the next lower version, unless set in the request.
1.0Your own data (JSON object, at most 16,384 bytes as UTF-8 JSON, nested at most 8 levels). mint stores and returns it unchanged and never uses it for the film. It is not part of the order identity.
Returns
The same order already exists (same video_key, version and content); the existing film is returned and nothing was created. Returns the film object.
The film was created. Returns the film object.
Location Path of the film: /api/v1/films/{id}.Errors 400 · 401 · 402 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
The company does not have enough credits for the requested automation (insufficient_credits). Nothing was created; add credits in mint and retry.
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Conflict (category_exists, external_key_exists, external_key_conflict, category_limit_reached, idempotency_in_progress, version_conflict, previous_version_creating, film_deleted, not_cancellable, file_unavailable, storyboard_not_ready, storyboard_not_current, timeline_outdated, preview_in_progress, preview_not_ready, preview_unsupported, feedback_queue_full, feedback_not_cancellable, feedback_not_retryable, feedback_busy, revision_locked, film_not_ready, film_busy, no_open_comments, comments_not_open, correction_in_progress, upload_quota_exceeded, film_cancelled).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"title": "Lesson 3: Market segmentation",
"narration_text": "Not every customer wants the same thing. In this lesson we look at how companies divide a market into groups …",
"user_email": "anna.schmidt@example.edu",
"language": "de",
"template": "lesson-standard",
"automation": "storyboard",
"category": {
"external_key": "MKT101"
},
"video_key": "MKT101-lesson-03",
"version": "1.0",
"metadata": {
"course_id": "MKT101",
"lesson": 3
}
}'const res = await fetch("https://api.cream-ai.de/api/v1/films", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Lesson 3: Market segmentation",
narration_text: "Not every customer wants the same thing. In this lesson we look at how companies divide a market into groups …",
user_email: "anna.schmidt@example.edu",
language: "de",
template: "lesson-standard",
automation: "storyboard",
category: {
external_key: "MKT101"
},
video_key: "MKT101-lesson-03",
version: "1.0",
metadata: {
course_id: "MKT101",
lesson: 3
}
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"title": "Lesson 3: Market segmentation",
"narration_text": "Not every customer wants the same thing. In this lesson we look at how companies divide a market into groups …",
"user_email": "anna.schmidt@example.edu",
"language": "de",
"template": "lesson-standard",
"automation": "storyboard",
"category": {
"external_key": "MKT101",
},
"video_key": "MKT101-lesson-03",
"version": "1.0",
"metadata": {
"course_id": "MKT101",
"lesson": 3,
},
},
)
data = res.json(){
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "in_production",
"stage": "planning",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": null,
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-10T08:00:04Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": null,
"subtitles_url": null,
"revisions": [],
"latest_revision": null
}The current state of a film ordered through the API, with its rendered revisions. Unknown ids, projects created in mint, films of other companies and films deleted in mint return 404 not_found.
Path parameters
Id of the film (id from POST /films or GET /films).
Returns
The film. Returns the film object.
Errors 401 · 403 · 404 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "approved",
"stage": "approved",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": {
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
}
},
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-11T14:30:00Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
"subtitles_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt",
"revisions": [
{
"revision": 1,
"status": "ready",
"created_at": "2026-11-10T08:21:37Z",
"finished_at": "2026-11-10T08:39:10Z",
"duration_s": 181.2,
"resolution": "1920x1080"
},
{
"revision": 2,
"status": "ready",
"created_at": "2026-11-11T13:50:00Z",
"finished_at": "2026-11-11T14:05:41Z",
"duration_s": 184.6,
"resolution": "1920x1080"
}
]
}Films of the company, sorted by created_at (oldest first), then id; new films usually appear at the end. Lists the films of the company that were ordered through the API; every active API access of the company can read them. Projects created in mint are not listed (other sources may be added later). Each film appears at most once while paging. A film created in the same second as a page is read can, rarely, be sorted before the cursor. With status mint filters while reading: a page can be shorter than limit (even empty) and still have has_more: true; keep paging with next_cursor. limit is 1–100. Title and category in the list can be up to 10 minutes behind mint; GET /films/{id} shows the current state. A film deleted in mint disappears from the list.
Query parameters
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Only films with this status.
briefing in_production storyboard_ready film_ready approved cancelledOnly films with this video_key (all versions, exact match, case-sensitive).
Only films in this category; for a top-level category also in its subcategories.
api: films ordered through the API (default and currently the only value; other sources may be added later).
apiapiReturns
One page of films.
Show response attributes
listShow child attributes
filmId of the film in mint.
Title as it is in mint now (people can change it there).
briefing: created in mint, nothing is running (for example with automation: none). in_production: mint is planning or producing the storyboard (or the film). storyboard_ready: the storyboard is ready for review in mint. With automation: storyboard the film stops here until a person continues in mint. film_ready: the film is rendered and waits for approval by a person in mint. approved: a person approved the film in mint. cancelled: the film was cancelled. New values may be added within v1.
Detailed stage as shown in the mint project list, or null if unknown. New values may be added within v1.
briefing style voice ready_to_plan planning storyboard_in_progress storyboard_review film_rendering film_ready approved paused error cancelledtrue if a person needs to act in mint (see notice).
Why a person needs to act in mint, or null. Codes: production_paused (“Production is paused in mint. Someone needs to resume it.”), production_failed (“Production failed in mint. Someone needs to check it.”), planning_failed (“Planning the storyboard failed in mint. Someone needs to check it.”), automation_failed (“The automatic storyboard could not be completed. Someone needs to continue in mint.”), insufficient_credits (“The company does not have enough credits. Someone needs to add credits and continue in mint.”), automation_disabled (“Automatic production is currently switched off. Someone needs to continue in mint.”).
Show child attributes
production_paused production_failed planning_failed automation_failed insufficient_credits automation_disabledShort English text (may change).
api: ordered through the API; app: reserved for projects created in mint (not returned in v1).
none: mint only creates the film with its briefing; people continue in mint. storyboard (default): mint plans and produces the storyboard automatically and stops at storyboard_ready for review. film: mint also renders the film without stopping at the storyboard (status film_ready). The film is always approved by a person in mint, never by the API.
Your key of the video, as sent.
Version of the video, canonical (1.0.0 is returned as 1.0).
Id of the film with the next lower version of the same video_key, or null.
true only if this film is approved and no higher, approved and not cancelled version of the same video_key exists.
Language of the film.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgKey of the template used when the film was created.
Effective settings of the film in mint. Values that are not set (or that mint cannot express in the API) are null.
Show child attributes
Aspect ratio.
16x9 9x16 1x1Id of the style (see GET /styles).
Revision of the style the film uses.
Effective brand (see GET /brands); null = no brand.
Voice of the narration (may also be a voice from the mint voice library); null = none set yet.
Name of the voice.
verbatim (default): narration_text is spoken word for word. smooth: mint polishes the language of narration_text and keeps its content. free: narration_text is the briefing; mint writes the narration freely (use target_duration_s for the length).
Pace of the film.
presenting lively kineticCreative freedom in percent.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds).
Category of the film in mint (see GET /categories), or null.
Show child attributes
categoryId of the category.
Key of the connected system, if set.
Top-level category of a subcategory; null for a top-level category.
Show child attributes
The mint user from user_email of the request (a Person with kind user). This user is responsible for the film in mint and is notified when the storyboard is ready. Personal data.
Show child attributes
Always user.
userE-mail address (lower case).
Name of the user at the time the film was created.
Your metadata, as sent. mint never uses it for the film. Key order is kept in POST /films (first response), GET /films and GET /films/{id}; a replayed response may order keys differently.
The active approval of the film (only the approved original version is the film), or null.
Show child attributes
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file, e.g. video/mp4.
true if subtitles were frozen with this approval (subtitles_url).
Who approved the film in mint (kind user, name and e-mail; email is null for approvals before 9 November 2026). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the cancellation (UTC), or null.
Creation time (UTC).
Last change (UTC).
Link to the film in mint (for people with access), or null.
Path of the approved file (GET /films/{id}/file, relative to the host of the API), or null without an active approval.
Path of the subtitles of the approval (GET /films/{id}/subtitles.srt), or null if the approval has none.
Rendered revisions of the film, newest last (only in GET /films/{id}, without file links).
Show child attributes
Number of the rendered revision.
rendering, ready or failed.
Start of the render (UTC).
End of the render (UTC), null while rendering.
Duration in seconds.
Resolution, e.g. 1920x1080.
true if more films may follow (also after a short or empty page when filtering by status).
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films?status=approved&limit=20" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films?status=approved&limit=20", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
params={
"status": "approved",
"limit": "20",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "approved",
"stage": "approved",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": {
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
}
},
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-11T14:30:00Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
"subtitles_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt"
}
],
"has_more": false,
"next_cursor": null
}Cancels a film ordered through the API, also while mint is planning or producing it automatically, until the storyboard is ready. Running planning and production are stopped; costs that already occurred stay. Once the storyboard (or the film) is ready, the film can no longer be cancelled through the API: 409 not_cancellable with details.reason (for example not_api_film for projects created in mint, other_client if another API access ordered the film, storyboard_ready). Only the API access that ordered the film can cancel it, unless that access was revoked or expired. Cancelling again returns 200 with the cancelled film. A cancelled film frees its video_key and version: the same order then creates a new film.
Path parameters
Id of the film (id from POST /films or GET /films).
Headers
Optional unique key of this write request (1–128 visible ASCII characters). Retries with the same key return the stored response.
Request body optional
Optional reason (at most 500 characters) for the cancellation.
Returns
The cancelled film. Returns the film object.
Errors 400 · 401 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Conflict (category_exists, external_key_exists, external_key_conflict, category_limit_reached, idempotency_in_progress, version_conflict, previous_version_creating, film_deleted, not_cancellable, file_unavailable, storyboard_not_ready, storyboard_not_current, timeline_outdated, preview_in_progress, preview_not_ready, preview_unsupported, feedback_queue_full, feedback_not_cancellable, feedback_not_retryable, feedback_busy, revision_locked, film_not_ready, film_busy, no_open_comments, comments_not_open, correction_in_progress, upload_quota_exceeded, film_cancelled).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/cancel" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "Lesson was removed from the course."
}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/cancel", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
reason: "Lesson was removed from the course."
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/cancel",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"reason": "Lesson was removed from the course.",
},
)
data = res.json(){
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "cancelled",
"stage": "cancelled",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": null,
"cancelled_at": "2026-11-10T08:05:10Z",
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-10T08:05:10Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": null,
"subtitles_url": null,
"revisions": [],
"latest_revision": null
}Downloads the approved file of a film ordered through the API (only the approved original version; format and language versions are not part of v1). The response is the file as video/mp4 with a strong ETag (the SHA-256 of the file, the same as approval.sha256 of the current approval). Compare it with the SHA-256 of the downloaded bytes. Resume an interrupted download with Range: bytes=<from>- and If-Range: <ETag>: 206 with the rest, or 200 with the whole file if the approval changed. A single range is supported; several ranges or an invalid one return the whole file. A range behind the end returns 416 range_not_satisfiable. With If-None-Match: <ETag> the response is 304 without a body when the approval is unchanged. HEAD returns the headers only. The download always returns the approval that is active now. If an event is older than the current approval, the ETag differs from data.approval.sha256 of the event; then the ETag counts. 404 not_approved: the film has no active approval (never approved or revoked). 409 file_unavailable: the file is missing or does not match the approval; mint is informed, retry later. 503 with Retry-After: mint is checking the file or is briefly unavailable, retry after the given seconds. At most a few downloads per company run at the same time (429 rate_limited with details.reason parallel_downloads and Retry-After). Downloads are free of credits.
Path parameters
Id of the film (id from POST /films, GET /films or film_id of an event).
Headers
One byte range, e.g. bytes=33554432-.
The ETag of the first response; the range only applies if it still matches.
The ETag you already have; 304 if unchanged.
Returns
The whole approved file.
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="<film_id>_r<revision>.<ext>".Cache-Control no-store, no-transform.The requested part of the approved file.
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="<film_id>_r<revision>.<ext>".Cache-Control no-store, no-transform.Content-Range bytes <from>-<to>/<size>.Unchanged (the ETag from If-None-Match still matches).
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Errors 401 · 403 · 404 · 409 · 416 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found) or not approved (not_approved).
The approved file is not available (file_unavailable). mint is informed; retry later.
The range is behind the end of the file (range_not_satisfiable).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file" \
-H "Authorization: Bearer $MINT_API_KEY" \
-o film.mp4import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.code);
await pipeline(Readable.fromWeb(res.body), createWriteStream("film.mp4"));
// Compare the SHA-256 of the file with res.headers.get("etag")import os
import requests
with requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
stream=True,
) as res:
res.raise_for_status()
with open("film.mp4", "wb") as f:
for chunk in res.iter_content(chunk_size=1 << 20):
f.write(chunk)
# Compare the SHA-256 of the file with res.headers["ETag"]HTTP/1.1 200 OK
Content-Type: video/mp4
X-Request-Id: req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c
ETag: "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
Accept-Ranges: bytes
Content-Length: 48213377
Content-Disposition: attachment; filename="k7m2xq9v4t8n1b5r3c6d0wza_r2.mp4"
Cache-Control: no-store, no-transform
<binary MP4 data>Downloads the subtitles (SubRip) that were frozen with the active approval of a film ordered through the API. Only the subtitles of the approval are returned, never a newer state: 404 subtitles_not_available if the approval has none (subtitles_url of the film is then null). ETag, If-None-Match, Range and HEAD work as for the film file.
Path parameters
Id of the film (id from POST /films, GET /films or film_id of an event).
Headers
One byte range.
The ETag of the first response.
The ETag you already have; 304 if unchanged.
Returns
The subtitles (UTF-8).
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="<film_id>_r<revision>.<ext>".Cache-Control no-store, no-transform.The requested part of the subtitles.
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="<film_id>_r<revision>.<ext>".Cache-Control no-store, no-transform.Content-Range bytes <from>-<to>/<size>.Unchanged.
ETag Strong ETag: the SHA-256 of the file in quotes. Compare it with the SHA-256 of the downloaded bytes.Errors 401 · 403 · 404 · 409 · 416 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found), not approved (not_approved) or the approval has no subtitles (subtitles_not_available).
The subtitles are not available (file_unavailable). mint is informed; retry later.
The range is behind the end of the file (range_not_satisfiable).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt" \
-H "Authorization: Bearer $MINT_API_KEY" \
-o film.srtimport { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.code);
await pipeline(Readable.fromWeb(res.body), createWriteStream("film.srt"));
// Compare the SHA-256 of the file with res.headers.get("etag")import os
import requests
with requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
stream=True,
) as res:
res.raise_for_status()
with open("film.srt", "wb") as f:
for chunk in res.iter_content(chunk_size=1 << 20):
f.write(chunk)
# Compare the SHA-256 of the file with res.headers["ETag"]HTTP/1.1 200 OK
Content-Type: application/x-subrip
X-Request-Id: req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c
ETag: "9f2c4e6a8b0d1f3e5a7c9b1d3f5e7a9c2b4d6f8e0a1c3e5b7d9f1a3c5e7b9d2f"
Accept-Ranges: bytes
Content-Length: 6214
Content-Disposition: attachment; filename="k7m2xq9v4t8n1b5r3c6d0wza_r2.srt"
Cache-Control: no-store, no-transform
1
00:00:00,000 --> 00:00:04,200
Not every customer wants the same thing.While mint produces a film, GET /films/{id}/progress shows how far it is: the production steps (narration, timeline, images and clips, scenes, film), how many scenes are done and a rough estimate of the remaining time. Reading the progress is free. Use it for a progress bar while a person is watching; for everything else, the event feed is enough.
Attributes
film_progressId of the film.
Status of the film, as in GET /films/{id}.
briefing in_production storyboard_ready film_ready approved cancelledDetailed stage, as in GET /films/{id}, or null if unknown. New values may be added within v1.
true if a person needs to act in mint, as in GET /films/{id}.
The latest production of the film, or null if there is none yet.
Show child attributes
queued, running, storyboard_ready (the storyboard is ready, no film is rendering), film_rendering, film_ready, failed or cancelled. New values may be added within v1.
Current step (see steps[].id).
audio timeline media scenes filmVersion of the storyboard this production works on.
Start of the production (UTC).
Last change of the production (UTC).
Steps of the production in order; empty without a production.
Show child attributes
audio, timeline, media, scenes or film. New values may be added within v1.
waiting running done failedParts of the step with their own progress (only present if the step has parts).
Show child attributes
Stable technical id of the part.
Display text of the part as shown in mint (German).
waiting running done failedProgress from 0 to 1, or null if unknown.
Start of the part (UTC), or null.
Scene counts of the current storyboard, or null without a production.
Show child attributes
Scenes of the current storyboard (sum of the other counts).
Finished in the current state.
Being created or changed right now.
Not started yet.
Finished, but in an older state of the storyboard.
The last change of the scene failed.
Rough estimate of the remaining time, or null.
Show child attributes
Estimated remaining seconds.
low or medium. Treat it as a rough guess.
scene_rate: from the scenes finished so far; film_render: from the progress of the film render. New values may be added within v1.
{
"object": "film_progress",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"status": "in_production",
"stage": "storyboard_in_progress",
"attention_required": false,
"production": {
"status": "running",
"phase": "scenes",
"storyboard_version": 1,
"started_at": "2026-11-10T08:00:04Z",
"updated_at": "2026-11-10T08:14:52Z"
},
"steps": [
{
"id": "scenes",
"status": "running",
"parts": [
{
"id": "scene-07",
"label": "Scene 7",
"status": "running",
"progress": 0.6,
"started_at": "2026-11-10T08:13:30Z"
}
]
}
],
"scenes": {
"total": 14,
"done": 9,
"rendering": 2,
"pending": 3,
"outdated": 0,
"failed": 0
},
"estimate": {
"remaining_s": 240,
"confidence": "medium",
"basis": "scene_rate"
}
}The production progress of a film ordered through the API. Reading it is free of credits and changes nothing. status, stage and attention_required are the same as in GET /films/{id}. Without a production (the film is still in the briefing, or mint has not started yet) production is null, steps is empty and scenes and estimate are null. steps follow the production in mint: audio (narration), timeline, media (images and clips), scenes (rendering the storyboard scenes) and film (rendering the film). A step can have parts with their own progress (0–1). scenes counts every scene of the current storyboard exactly once: done (current and finished), rendering (being created or changed right now), failed (the last change of this scene failed), outdated (finished, but an older state) and pending (the rest). estimate is a rough guess of the remaining seconds, only while scenes or the film are rendering and once there is enough data; otherwise null. Do not use it for deadlines. The response can be up to 5 seconds old. Poll at most every few seconds, or follow the event feed. Unknown ids, projects created in mint, films of other companies and films deleted in mint return 404 not_found. New values in steps[].id, production.phase and production.status may be added within v1.
Path parameters
Id of the film (id from POST /films or GET /films).
Returns
The progress of the film. Returns the film progress object.
Errors 401 · 403 · 404 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
The film was not found (not_found): unknown id, a project created in mint, a film of another company or a film deleted in mint.
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/progress" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/progress", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/progress",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "film_progress",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"status": "in_production",
"stage": "storyboard_in_progress",
"attention_required": false,
"production": {
"status": "running",
"phase": "scenes",
"storyboard_version": 1,
"started_at": "2026-11-10T08:00:04Z",
"updated_at": "2026-11-10T08:14:52Z"
},
"steps": [
{
"id": "scenes",
"status": "running",
"parts": [
{
"id": "scene-07",
"label": "Scene 7",
"status": "running",
"progress": 0.6,
"started_at": "2026-11-10T08:13:30Z"
}
]
}
],
"scenes": {
"total": 14,
"done": 9,
"rendering": 2,
"pending": 3,
"outdated": 0,
"failed": 0
},
"estimate": {
"remaining_s": 240,
"confidence": "medium",
"basis": "scene_rate"
}
}Events tell you what happened to films ordered through the API, in a fixed order per company. See Event feed for the recommended way to consume them.
Attributes
eventStable id of the event (evt_<seq>).
Position in the feed; grows within your company (with gaps).
Type of the event. Known types: film.created, film.status_changed, film.storyboard_ready, film.approved, film.approval_revoked, film.cancelled, film.deleted, film.progress, feedback.updated, storyboard.preview_ready, operation.completed. New types may be added.
Time of the change (UTC).
Id of the film.
Snapshot at the time of the event: status (after the event), previous_status, approval, and the person who triggered the event (requested_by, cancelled_by, approval.approved_by, approval.revoked_by; personal data).
Show child attributes
Status of the film after the event.
briefing in_production storyboard_ready film_ready approved cancelledStatus before the event (null if the feed did not know the film yet).
Snapshot of the approval at the time of the event (in film.approved complete, in film.approval_revoked only id and revision).
Show child attributes
Id of the approval.
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file.
true if subtitles were frozen with this approval.
film.approved: who approved the film in mint. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.approval_revoked: who revoked the approval in mint. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.created: the mint user from user_email of the order. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.cancelled: the API access that cancelled the film (kind api). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
The current film (as GET /films/{id}, without revisions); null if it was deleted. Only present with the scope films:read.
Show child attributes
filmId of the film in mint.
Title as it is in mint now (people can change it there).
briefing: created in mint, nothing is running (for example with automation: none). in_production: mint is planning or producing the storyboard (or the film). storyboard_ready: the storyboard is ready for review in mint. With automation: storyboard the film stops here until a person continues in mint. film_ready: the film is rendered and waits for approval by a person in mint. approved: a person approved the film in mint. cancelled: the film was cancelled. New values may be added within v1.
Detailed stage as shown in the mint project list, or null if unknown. New values may be added within v1.
briefing style voice ready_to_plan planning storyboard_in_progress storyboard_review film_rendering film_ready approved paused error cancelledtrue if a person needs to act in mint (see notice).
Why a person needs to act in mint, or null. Codes: production_paused (“Production is paused in mint. Someone needs to resume it.”), production_failed (“Production failed in mint. Someone needs to check it.”), planning_failed (“Planning the storyboard failed in mint. Someone needs to check it.”), automation_failed (“The automatic storyboard could not be completed. Someone needs to continue in mint.”), insufficient_credits (“The company does not have enough credits. Someone needs to add credits and continue in mint.”), automation_disabled (“Automatic production is currently switched off. Someone needs to continue in mint.”).
Show child attributes
production_paused production_failed planning_failed automation_failed insufficient_credits automation_disabledShort English text (may change).
api: ordered through the API; app: reserved for projects created in mint (not returned in v1).
none: mint only creates the film with its briefing; people continue in mint. storyboard (default): mint plans and produces the storyboard automatically and stops at storyboard_ready for review. film: mint also renders the film without stopping at the storyboard (status film_ready). The film is always approved by a person in mint, never by the API.
Your key of the video, as sent.
Version of the video, canonical (1.0.0 is returned as 1.0).
Id of the film with the next lower version of the same video_key, or null.
true only if this film is approved and no higher, approved and not cancelled version of the same video_key exists.
Language of the film.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgKey of the template used when the film was created.
Effective settings of the film in mint. Values that are not set (or that mint cannot express in the API) are null.
Show child attributes
Aspect ratio.
16x9 9x16 1x1Id of the style (see GET /styles).
Revision of the style the film uses.
Effective brand (see GET /brands); null = no brand.
Voice of the narration (may also be a voice from the mint voice library); null = none set yet.
Name of the voice.
verbatim (default): narration_text is spoken word for word. smooth: mint polishes the language of narration_text and keeps its content. free: narration_text is the briefing; mint writes the narration freely (use target_duration_s for the length).
Pace of the film.
presenting lively kineticCreative freedom in percent.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds).
Category of the film in mint (see GET /categories), or null.
Show child attributes
categoryId of the category.
Key of the connected system, if set.
Top-level category of a subcategory; null for a top-level category.
Show child attributes
The mint user from user_email of the request (a Person with kind user). This user is responsible for the film in mint and is notified when the storyboard is ready. Personal data.
Show child attributes
Always user.
userE-mail address (lower case).
Name of the user at the time the film was created.
Your metadata, as sent. mint never uses it for the film. Key order is kept in POST /films (first response), GET /films and GET /films/{id}; a replayed response may order keys differently.
The active approval of the film (only the approved original version is the film), or null.
Show child attributes
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file, e.g. video/mp4.
true if subtitles were frozen with this approval (subtitles_url).
Who approved the film in mint (kind user, name and e-mail; email is null for approvals before 9 November 2026). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the cancellation (UTC), or null.
Creation time (UTC).
Last change (UTC).
Link to the film in mint (for people with access), or null.
Path of the approved file (GET /films/{id}/file, relative to the host of the API), or null without an active approval.
Path of the subtitles of the approval (GET /films/{id}/subtitles.srt), or null if the approval has none.
Rendered revisions of the film, newest last (only in GET /films/{id}, without file links).
Show child attributes
Number of the rendered revision.
rendering, ready or failed.
Start of the render (UTC).
End of the render (UTC), null while rendering.
Duration in seconds.
Resolution, e.g. 1920x1080.
{
"object": "event",
"id": "evt_10482",
"seq": 10482,
"type": "film.approved",
"occurred_at": "2026-11-11T14:30:00Z",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"data": {
"status": "approved",
"previous_status": "film_ready",
"approval": {
"id": "apr_20931",
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"revoked_by": null
},
"requested_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"cancelled_by": null
},
"film": {
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "approved",
"stage": "approved",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": {
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
}
},
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-11T14:30:00Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
"subtitles_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt"
}
}The event feed of your company: every change of a film ordered through the API that matters to you, in a fixed order. Each event has a seq that grows within your company. Read the feed with after = next_after of the previous page (start with 0) and store next_after only after you processed the page. Duplicates (at least once) can be recognized by id. data is a snapshot at the time of the event. film is the current state of the film (as GET /films/{id}, without revisions) and is only present if the API key also has the scope films:read; it is null for a film that was deleted in mint. Types: film.created, film.status_changed (every change of status), film.storyboard_ready (once per storyboard), film.approved, film.approval_revoked, film.cancelled, film.deleted. A specific event comes before its film.status_changed. New types may be added within v1; ignore types you do not know. mint keeps events for 180 days. An after older than that returns 410 cursor_expired; an after ahead of the feed (for example from another mint server) returns 400 invalid_cursor. In both cases start again: note latest_seq, read GET /films?status=approved, then continue with after = the noted latest_seq. mint writes events together with the change. In rare cases an event comes up to 10 minutes late; intermediate states can then be missing, the final state is always reported.
Query parameters
Return events with a seq greater than this (next_after of the previous page). Default 0 (from the oldest kept event).
0Comma-separated list of event types (default: all). Known types: film.created, film.status_changed, film.storyboard_ready, film.approved, film.approval_revoked, film.cancelled, film.deleted, film.progress, feedback.updated, storyboard.preview_ready, operation.completed.
api: films ordered through the API (default and currently the only value).
apiapiPage size (1–100).
50 · 1–100Returns
One page of events.
Show response attributes
listShow child attributes
eventStable id of the event (evt_<seq>).
Position in the feed; grows within your company (with gaps).
Type of the event. Known types: film.created, film.status_changed, film.storyboard_ready, film.approved, film.approval_revoked, film.cancelled, film.deleted, film.progress, feedback.updated, storyboard.preview_ready, operation.completed. New types may be added.
Time of the change (UTC).
Id of the film.
Snapshot at the time of the event: status (after the event), previous_status, approval, and the person who triggered the event (requested_by, cancelled_by, approval.approved_by, approval.revoked_by; personal data).
Show child attributes
Status of the film after the event.
briefing in_production storyboard_ready film_ready approved cancelledStatus before the event (null if the feed did not know the film yet).
Snapshot of the approval at the time of the event (in film.approved complete, in film.approval_revoked only id and revision).
Show child attributes
Id of the approval.
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file.
true if subtitles were frozen with this approval.
film.approved: who approved the film in mint. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.approval_revoked: who revoked the approval in mint. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.created: the mint user from user_email of the order. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
film.cancelled: the API access that cancelled the film (kind api). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
The current film (as GET /films/{id}, without revisions); null if it was deleted. Only present with the scope films:read.
Show child attributes
filmId of the film in mint.
Title as it is in mint now (people can change it there).
briefing: created in mint, nothing is running (for example with automation: none). in_production: mint is planning or producing the storyboard (or the film). storyboard_ready: the storyboard is ready for review in mint. With automation: storyboard the film stops here until a person continues in mint. film_ready: the film is rendered and waits for approval by a person in mint. approved: a person approved the film in mint. cancelled: the film was cancelled. New values may be added within v1.
Detailed stage as shown in the mint project list, or null if unknown. New values may be added within v1.
briefing style voice ready_to_plan planning storyboard_in_progress storyboard_review film_rendering film_ready approved paused error cancelledtrue if a person needs to act in mint (see notice).
Why a person needs to act in mint, or null. Codes: production_paused (“Production is paused in mint. Someone needs to resume it.”), production_failed (“Production failed in mint. Someone needs to check it.”), planning_failed (“Planning the storyboard failed in mint. Someone needs to check it.”), automation_failed (“The automatic storyboard could not be completed. Someone needs to continue in mint.”), insufficient_credits (“The company does not have enough credits. Someone needs to add credits and continue in mint.”), automation_disabled (“Automatic production is currently switched off. Someone needs to continue in mint.”).
Show child attributes
production_paused production_failed planning_failed automation_failed insufficient_credits automation_disabledShort English text (may change).
api: ordered through the API; app: reserved for projects created in mint (not returned in v1).
none: mint only creates the film with its briefing; people continue in mint. storyboard (default): mint plans and produces the storyboard automatically and stops at storyboard_ready for review. film: mint also renders the film without stopping at the storyboard (status film_ready). The film is always approved by a person in mint, never by the API.
Your key of the video, as sent.
Version of the video, canonical (1.0.0 is returned as 1.0).
Id of the film with the next lower version of the same video_key, or null.
true only if this film is approved and no higher, approved and not cancelled version of the same video_key exists.
Language of the film.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgKey of the template used when the film was created.
Effective settings of the film in mint. Values that are not set (or that mint cannot express in the API) are null.
Show child attributes
Aspect ratio.
16x9 9x16 1x1Id of the style (see GET /styles).
Revision of the style the film uses.
Effective brand (see GET /brands); null = no brand.
Voice of the narration (may also be a voice from the mint voice library); null = none set yet.
Name of the voice.
verbatim (default): narration_text is spoken word for word. smooth: mint polishes the language of narration_text and keeps its content. free: narration_text is the briefing; mint writes the narration freely (use target_duration_s for the length).
Pace of the film.
presenting lively kineticCreative freedom in percent.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds).
Category of the film in mint (see GET /categories), or null.
Show child attributes
categoryId of the category.
Key of the connected system, if set.
Top-level category of a subcategory; null for a top-level category.
Show child attributes
The mint user from user_email of the request (a Person with kind user). This user is responsible for the film in mint and is notified when the storyboard is ready. Personal data.
Show child attributes
Always user.
userE-mail address (lower case).
Name of the user at the time the film was created.
Your metadata, as sent. mint never uses it for the film. Key order is kept in POST /films (first response), GET /films and GET /films/{id}; a replayed response may order keys differently.
The active approval of the film (only the approved original version is the film), or null.
Show child attributes
Approved revision of the film.
Time of the approval (UTC).
SHA-256 of the approved file (hex).
Size of the approved file in bytes.
Duration in seconds.
Resolution, e.g. 1920x1080.
Media type of the file, e.g. video/mp4.
true if subtitles were frozen with this approval (subtitles_url).
Who approved the film in mint (kind user, name and e-mail; email is null for approvals before 9 November 2026). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the cancellation (UTC), or null.
Creation time (UTC).
Last change (UTC).
Link to the film in mint (for people with access), or null.
Path of the approved file (GET /films/{id}/file, relative to the host of the API), or null without an active approval.
Path of the subtitles of the approval (GET /films/{id}/subtitles.srt), or null if the approval has none.
Rendered revisions of the film, newest last (only in GET /films/{id}, without file links).
Show child attributes
Number of the rendered revision.
rendering, ready or failed.
Start of the render (UTC).
End of the render (UTC), null while rendering.
Duration in seconds.
Resolution, e.g. 1920x1080.
true if more events follow right away.
Pass as after to continue. Store it only after you processed the page.
The newest position of the feed of your company (for a restart, see above).
Errors 400 · 401 · 403 · 410 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
This position is no longer kept (cursor_expired, details.min_after, details.latest_seq). Start again with latest_seq and GET /films?status=approved.
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/events?after=10480&types=film.approved,film.approval_revoked,film.deleted" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/events?after=10480&types=film.approved,film.approval_revoked,film.deleted", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/events",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
params={
"after": "10480",
"types": "film.approved,film.approval_revoked,film.deleted",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "event",
"id": "evt_10482",
"seq": 10482,
"type": "film.approved",
"occurred_at": "2026-11-11T14:30:00Z",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"data": {
"status": "approved",
"previous_status": "film_ready",
"approval": {
"id": "apr_20931",
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"revoked_by": null
},
"requested_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"cancelled_by": null
},
"film": {
"object": "film",
"id": "k7m2xq9v4t8n1b5r3c6d0wza",
"title": "Lesson 3: Market segmentation",
"status": "approved",
"stage": "approved",
"attention_required": false,
"notice": null,
"source": "api",
"automation": "storyboard",
"video_key": "MKT101-lesson-03",
"version": "1.0",
"previous_version_id": null,
"is_latest_approved_version": true,
"language": "de",
"template": "lesson-standard",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"style_revision": 4,
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"voice_name": "Clara",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"category": {
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"external_key": "MKT101",
"parent": {
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"external_key": "MKT"
}
},
"requested_by": {
"kind": "user",
"email": "anna.schmidt@example.edu",
"name": "Anna Schmidt"
},
"metadata": {
"course_id": "MKT101",
"lesson": 3
},
"approval": {
"revision": 2,
"approved_at": "2026-11-11T14:30:00Z",
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"bytes": 48213377,
"duration_s": 184.6,
"resolution": "1920x1080",
"mime": "video/mp4",
"has_subtitles": true,
"approved_by": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
}
},
"cancelled_at": null,
"created_at": "2026-11-10T08:00:00Z",
"updated_at": "2026-11-11T14:30:00Z",
"app_url": "https://app.cream-ai.de/editorial/k7m2xq9v4t8n1b5r3c6d0wza",
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/file",
"subtitles_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/subtitles.srt"
}
}
],
"has_more": false,
"next_after": 10482,
"latest_seq": 10482
}A storyboard preview is an MP4 (1280x720) of the current storyboard: the scene clips in film order with the voice-over and a visible watermark. Use it to review a film in your own system before it is finished, for example together with feedback on single scenes.
- Each new preview costs credits (currently 100). A preview of an unchanged storyboard is reused and not charged again.
- Creating a preview is a long-running operation: you get
202and poll the operation. - Previews are kept for a limited time (
expires_at); after that, request a new one. - A preview is never the approved film.
Attributes
storyboard_previewId of the preview.
Id of the film.
queued rendering ready failed expiredVersion of the storyboard the preview shows.
true if every scene is current and the preview belongs to the current storyboard.
Duration in seconds (planned until ready).
Frames per second.
Resolution, e.g. 1280x720.
Size of the file in bytes (when ready).
SHA-256 of the file (hex, when ready); the same as the ETag of the download.
true: the preview carries a visible watermark.
Show child attributes
Number of the scene.
Start of the scene in the preview (seconds).
End of the scene in the preview (seconds).
current: clip of the current version; stale: clip of an earlier version (marked „outdated“); missing: no clip yet (dark panel).
Path of the file download (when ready).
Time of the request (UTC).
Time the preview became ready (UTC).
Time the preview expires (UTC); afterwards the file is deleted.
{
"object": "storyboard_preview",
"id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"status": "ready",
"storyboard_version": 1,
"current": true,
"duration_s": 181.2,
"fps": 25,
"resolution": "1280x720",
"bytes": 18342210,
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"watermark": true,
"scenes": [
{
"nr": 1,
"start_s": 0,
"end_s": 12.4,
"state": "current"
},
{
"nr": 2,
"start_s": 12.4,
"end_s": 25.9,
"state": "current"
}
],
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview/file?preview_id=pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"created_at": "2026-11-10T08:25:00Z",
"ready_at": "2026-11-10T08:27:41Z",
"expires_at": "2026-11-24T08:27:41Z"
}Request a storyboard preview (costs credits)
/api/v1/films/{id}/storyboard-previewHas mint create a storyboard preview of the film: one MP4 (1280x720) with the current scene clips in film order, the voice-over and a visible watermark „PREVIEW · Scene n“. It is not the finished film and never replaces the approval in mint. The preview is optional. Each new preview costs credits according to the mint price list (currently 100 credits); mint books them on the company in the name of the user from user_email of the order, after the preview is ready. A failed preview is not charged. When requesting, the company must have enough credits for this preview and for all of its previews that are still being created or not charged yet; otherwise the response is 402 insufficient_credits with details.required_credits (the credits needed for all of them) and nothing is created. The response is an operation (202 Accepted, Location: /api/v1/operations/{id}). Poll it until status is succeeded; result.url then points to the preview. If a ready preview of exactly the same storyboard state exists, the response is 200 with an operation that has already succeeded and reused: true; it points to that preview and is not charged again. If the same state is being created right now, the response is 202 with reused: true. Scenes that are not up to date are shown as „outdated“ or as a dark panel „is still being rendered“. With require_current: true the request is rejected with 409 storyboard_not_current (details.scenes) as long as a scene is not up to date. 409 storyboard_not_ready: the film has no storyboard yet. 409 preview_in_progress (details.operation_id): a preview of another state of this film is still being created; retry later. 409 preview_unsupported: previews are not available for this kind of film. 409 film_cancelled: the film was cancelled through the API; existing previews can still be read. 503 with details.feature storyboard_preview: previews are switched off right now. Rejections with a passing reason (storyboard_not_ready, preview_in_progress, insufficient_credits) are not stored under the Idempotency-Key: a retry with the same key runs again. The operation stays bound to its key: the same key with another request returns 422 idempotency_mismatch, also after 24 hours.
Path parameters
Id of the film (id from POST /films or GET /films).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body optional
true: only create the preview if every scene is up to date (otherwise 409 storyboard_not_current). Default false: outdated and missing scenes are marked in the preview.
falseReturns
A ready preview of the same storyboard state exists (status succeeded, reused: true, not charged again), or the operation of this Idempotency-Key has already finished.
Location Path of the operation: /api/v1/operations/{id}.Show response attributes
operationKind of operation. New types may be added within v1; ignore operations of unknown types.
storyboard.preview film.comments_applyqueued running succeeded failedCreation time (UTC).
Last change (UTC).
Show child attributes
Show child attributes
true if the request reuses a preview of the same storyboard state (ready or being created); it is not charged again.
The preview is being created (or the same state is already being created, reused: true). Poll the operation from Location.
Location Path of the operation: /api/v1/operations/{id}.Show response attributes
operationKind of operation. New types may be added within v1; ignore operations of unknown types.
storyboard.preview film.comments_applyqueued running succeeded failedCreation time (UTC).
Last change (UTC).
Show child attributes
Show child attributes
true if the request reuses a preview of the same storyboard state (ready or being created); it is not charged again.
Errors 400 · 401 · 402 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
The company does not have enough credits for a preview (insufficient_credits, details.required_credits). Nothing was created; not stored under the Idempotency-Key.
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
No storyboard yet (storyboard_not_ready), scenes not up to date with require_current (storyboard_not_current, details.scenes), a preview of another state is being created (preview_in_progress, details.operation_id), previews not available for this film (preview_unsupported), the film was cancelled through the API (film_cancelled), or a request with this Idempotency-Key is still running (idempotency_in_progress).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={},
)
data = res.json(){
"object": "operation",
"id": "op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a",
"type": "storyboard.preview",
"status": "queued",
"created_at": "2026-11-10T08:25:00Z",
"updated_at": "2026-11-10T08:25:00Z",
"result": null,
"error": null,
"reused": false
}Returns a storyboard preview of the film: without preview_id the newest one, otherwise the one with this id (result.id of the operation). status: queued, rendering, ready, failed or expired (previews are kept for a limited time, see expires_at). scenes shows the time range and state of each scene in the preview (current, stale = from an earlier version, missing = not rendered yet). current is true if every scene is up to date and the preview belongs to the current storyboard. Download the file with file_url as soon as status is ready.
Path parameters
Id of the film (id from POST /films or GET /films).
Query parameters
Id of the preview (result.id of the operation). Default: the newest preview of the film.
Returns
The storyboard preview. Returns the storyboard preview object.
Errors 400 · 401 · 403 · 404 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
The film or the preview was not found, or the film has no preview yet (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "storyboard_preview",
"id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"status": "ready",
"storyboard_version": 1,
"current": true,
"duration_s": 181.2,
"fps": 25,
"resolution": "1280x720",
"bytes": 18342210,
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"watermark": true,
"scenes": [
{
"nr": 1,
"start_s": 0,
"end_s": 12.4,
"state": "current"
},
{
"nr": 2,
"start_s": 12.4,
"end_s": 25.9,
"state": "current"
}
],
"file_url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview/file?preview_id=pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"created_at": "2026-11-10T08:25:00Z",
"ready_at": "2026-11-10T08:27:41Z",
"expires_at": "2026-11-24T08:27:41Z"
}Download the MP4 of a storyboard preview
/api/v1/films/{id}/storyboard-preview/fileDownloads the MP4 of a storyboard preview (without preview_id the newest one). The preview is not approved and carries a watermark. The response is video/mp4 with a strong ETag (the SHA-256 of the file in quotes, the same as sha256 of the preview). Resume an interrupted download with Range: bytes=<from>- and If-Range: <ETag>. A single range is supported; several or invalid ranges return the whole file; a range behind the end returns 416 range_not_satisfiable. With If-None-Match: <ETag> the response is 304 without a body. HEAD returns the headers only. 409 preview_not_ready: the preview is not ready yet. 410 preview_expired: the preview has expired; request a new one. 409 file_unavailable: the file is currently not available; retry later. Downloads are free of credits.
Path parameters
Id of the film (id from POST /films or GET /films).
Query parameters
Id of the preview. Default: the newest preview of the film.
Headers
One byte range, e.g. bytes=1048576-.
The ETag of the first response; the range only applies if it still matches.
The ETag you already have; 304 if unchanged.
Returns
The whole file.
ETag Strong ETag: the SHA-256 of the file in quotes (the same as sha256 of the preview).Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="storyboard-v<storyboard_version>.mp4".Cache-Control no-store, no-transform.The requested part of the file.
ETag Strong ETag: the SHA-256 of the file in quotes (the same as sha256 of the preview).Accept-Ranges bytes: downloads can be resumed with Range.Content-Length Length of the body in bytes.Content-Disposition attachment; filename="storyboard-v<storyboard_version>.mp4".Cache-Control no-store, no-transform.Content-Range bytes <from>-<to>/<size>.Unchanged (the ETag from If-None-Match still matches).
ETag Strong ETag: the SHA-256 of the file in quotes (the same as sha256 of the preview).Errors 400 · 401 · 403 · 404 · 409 · 410 · 416 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
The film or the preview was not found, or the film has no preview yet (not_found).
The preview is not ready yet (preview_not_ready) or its file is currently not available (file_unavailable).
The preview has expired (preview_expired). Request a new one.
The range is behind the end of the file (range_not_satisfiable).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview/file" \
-H "Authorization: Bearer $MINT_API_KEY" \
-o preview.mp4import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview/file", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.code);
await pipeline(Readable.fromWeb(res.body), createWriteStream("preview.mp4"));
// Compare the SHA-256 of the file with res.headers.get("etag")import os
import requests
with requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview/file",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
stream=True,
) as res:
res.raise_for_status()
with open("preview.mp4", "wb") as f:
for chunk in res.iter_content(chunk_size=1 << 20):
f.write(chunk)
# Compare the SHA-256 of the file with res.headers["ETag"]HTTP/1.1 200 OK
Content-Type: video/mp4
X-Request-Id: req_5b2e8f1a4c7d0e3b6a9f2c5d8e1b4a7c
ETag: "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
Accept-Ranges: bytes
Content-Length: 18342210
Content-Disposition: attachment; filename="storyboard-v1.mp4"
Cache-Control: no-store, no-transform
<binary MP4 data>Feedback changes scenes of the storyboard, like a message in the mint chat. Each entry names a scene (scene), a time (at_s) or both, and says what to change. mint plans and applies every entry on its own and never asks back.
- Optionally request a storyboard preview and refer to it with
preview_id. - Send one or more entries with
POST /films/{id}/feedback. Attach images with uploads. - Follow each entry:
queued→applying→applied, orfailed/discarded. Poll the entry or listen forfeedback.updatedevents. - A failed entry can be sent again with
POST /films/{id}/feedback/{feedback_id}/retry.
Feedback can cost credits according to the mint price list. Redrawing a scene at a fixed price only happens with allow_redraw: true.
Attributes
feedbackId of the request (id of the batch).
Id of the film.
Number of the scene.
Time from the request.
Time within the scene (seconds from its start).
Preview the time refers to.
Storyboard version at the time of the request.
text image layout generalThe feedback as sent.
Area of the frame as fractions of width and height (0..1, origin top left). It is cut to the frame.
Show child attributes
Width; the area must be greater than 0.
Height; the area must be greater than 0.
Point in the frame as fractions of width and height (0..1, origin top left).
Show child attributes
Show child attributes
Id of the upload.
Id of the file in the media of the film.
queued: waiting for the scene; applying: being planned or applied (see stage); applied: the scene was changed; failed: not applied (see failure, retry possible); discarded: cancelled via the API or stopped in mint.
Only for applying: planning, waiting_for_scene (the scene is rendering), applying, rendering.
Only for queued: scene_busy (another change of the scene is running), storyboard_busy (the storyboard is being created), service_unavailable (retried automatically).
Hints for the entry, e.g. timeline_may_be_outdated or scene_changed_since_preview. New values may be added.
Show child attributes
What mint changed (German, as in the mint chat).
Kind of change.
text image layout redraw regenerate noneStoryboard version with the change.
pending: the scene is not rendered yet; done: rendered.
Show child attributes
Reason (for failed and discarded). New codes may be added within v1; treat unknown codes like apply_failed.
English description of the reason.
The text mint shows in the chat (German), if any.
true for failed: POST …/retry is possible.
Only for redraw_required: the current fixed price of redrawing the scene from the mint price list (may change). Retry with allow_redraw: true to accept it.
Who sent the entry: the API access that sent (or last retried) it. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the request (UTC).
Last change of the state (UTC).
{
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "queued",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": null,
"failure": null,
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:31:02Z"
}Sends feedback on scenes of the storyboard, like a message in the mint chat. mint plans and applies each entry on its own; it never asks back but decides on the most plausible reading. Approving the film stays with a person in mint. Each entry names a scene (scene), a time in the film (at_s) or both. With preview_id the time refers to that storyboard preview; without it, to the current timeline of the film. Several entries for the same scene are applied one after the other in the order of entries. The entries are queued (status: queued) and handed over as soon as the scene is free. Poll GET /films/{id}/feedback/{feedback_id} or listen for feedback.updated events. Credits: planning and rendering cost credits according to the mint price list, booked on the company in the name of the user from user_email of the order. A redraw of a scene at a fixed price only happens with allow_redraw: true. If the company does not have enough credits, the response is 402 insufficient_credits and nothing is created. Attachments are upload ids of your company (POST /uploads). The request is all or nothing: if one entry is invalid, no entry is created (field names the entry, e.g. entries[1].message). The batch stays bound to its Idempotency-Key: the same key with the same request returns the same entries (also after 24 hours), with another request 422 idempotency_mismatch. Rejections with a passing reason (storyboard_not_ready, insufficient_credits) are not stored under the key: a retry with the same key runs again. A film cancelled through the API (status: cancelled) takes no more feedback: 409 film_cancelled. Its feedback can still be read and cancelled.
Path parameters
Id of the film (id from POST /films or GET /films).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body
Storyboard preview the times (at_s) refer to. It must belong to the current storyboard of the film.
Show child attributes
Number of the scene in the current storyboard.
Time in the film (or in the preview from preview_id) in seconds; it selects the scene at that time.
What the feedback is about. timing and voice are not supported (400 feedback_kind_unsupported).
generalThe feedback in your words (3 to 20000 characters after trimming; at most 100000 characters per request).
Area of the frame as fractions of width and height (0..1, origin top left). It is cut to the frame.
Show child attributes
Width; the area must be greater than 0.
Height; the area must be greater than 0.
Point in the frame as fractions of width and height (0..1, origin top left).
Show child attributes
Upload ids of your company (at most 4 per entry, 20 different per request). Unknown or foreign uploads: 400 upload_not_found; expired: 410 upload_expired.
true: mint may redraw the scene at a fixed price if the change needs it. Otherwise such an entry fails with redraw_required.
falseYour own reference (e.g. a ticket id); returned unchanged and in feedback.updated events.
Returns
The entries were queued (or the entries of this Idempotency-Key are returned again).
Show response attributes
feedback_batchId of the request; bound to its Idempotency-Key.
Id of the film.
The entries in the order of entries.
Show child attributes
feedbackId of the request (id of the batch).
Id of the film.
Number of the scene.
Time from the request.
Time within the scene (seconds from its start).
Preview the time refers to.
Storyboard version at the time of the request.
text image layout generalThe feedback as sent.
Area of the frame as fractions of width and height (0..1, origin top left). It is cut to the frame.
Show child attributes
Width; the area must be greater than 0.
Height; the area must be greater than 0.
Point in the frame as fractions of width and height (0..1, origin top left).
Show child attributes
Show child attributes
Id of the upload.
Id of the file in the media of the film.
queued: waiting for the scene; applying: being planned or applied (see stage); applied: the scene was changed; failed: not applied (see failure, retry possible); discarded: cancelled via the API or stopped in mint.
Only for applying: planning, waiting_for_scene (the scene is rendering), applying, rendering.
Only for queued: scene_busy (another change of the scene is running), storyboard_busy (the storyboard is being created), service_unavailable (retried automatically).
Hints for the entry, e.g. timeline_may_be_outdated or scene_changed_since_preview. New values may be added.
Show child attributes
What mint changed (German, as in the mint chat).
Kind of change.
text image layout redraw regenerate noneStoryboard version with the change.
pending: the scene is not rendered yet; done: rendered.
Show child attributes
Reason (for failed and discarded). New codes may be added within v1; treat unknown codes like apply_failed.
English description of the reason.
The text mint shows in the chat (German), if any.
true for failed: POST …/retry is possible.
Only for redraw_required: the current fixed price of redrawing the scene from the mint price list (may change). Retry with allow_redraw: true to accept it.
Who sent the entry: the API access that sent (or last retried) it. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the request (UTC).
Last change of the state (UTC).
Errors 400 · 401 · 402 · 403 · 404 · 409 · 410 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
The company does not have enough credits (insufficient_credits). Nothing was created; not stored under the Idempotency-Key.
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
The film was not found, or the preview from preview_id was not found (not_found, field: preview_id).
The film was cancelled through the API (film_cancelled), no storyboard yet (storyboard_not_ready), the timeline no longer matches (timeline_outdated, details.reason: preview_from_previous_storyboard or scene_boundaries_changed), too many open entries for this film (feedback_queue_full, details.open, details.limit), or a request with this Idempotency-Key is still running (idempotency_in_progress).
An attachment has expired (upload_expired, field names it). Upload the file again.
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch, details.batch_id), or a scene or time is not in the current storyboard (scene_not_found, field names the entry).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"entries": [
{
"scene": 4,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"external_ref": "lms-review-8812"
}
]
}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
preview_id: "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
entries: [
{
scene: 4,
kind: "text",
message: "Please write \"customer groups\" instead of \"target groups\" in the headline.",
external_ref: "lms-review-8812"
}
]
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"entries": [
{
"scene": 4,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"external_ref": "lms-review-8812",
},
],
},
)
data = res.json(){
"object": "feedback_batch",
"id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"data": [
{
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "queued",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": null,
"failure": null,
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:31:02Z"
}
]
}Returns one feedback entry with its current state.
Path parameters
Id of the film (id from POST /films or GET /films).
Id of the feedback entry (id from the feedback object).
Returns
The feedback entry. Returns the feedback object.
Errors 401 · 403 · 404 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "applied",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": {
"summary": "Headline changed to \"Customer groups\".",
"action": "text",
"storyboard_version": 2,
"render": "done"
},
"failure": null,
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:36:18Z"
}Lists the feedback entries of the film, newest first. Filter with status; the filter uses the state of the last feedback.updated event, the objects always show the current state.
Path parameters
Id of the film (id from POST /films or GET /films).
Query parameters
Only entries with this status.
queued applying applied failed discardedOpaque cursor from next_cursor of the previous page.
Page size (1–100).
50 · 1–100Returns
One page of feedback entries.
Show response attributes
listShow child attributes
feedbackId of the request (id of the batch).
Id of the film.
Number of the scene.
Time from the request.
Time within the scene (seconds from its start).
Preview the time refers to.
Storyboard version at the time of the request.
text image layout generalThe feedback as sent.
Area of the frame as fractions of width and height (0..1, origin top left). It is cut to the frame.
Show child attributes
Width; the area must be greater than 0.
Height; the area must be greater than 0.
Point in the frame as fractions of width and height (0..1, origin top left).
Show child attributes
Show child attributes
Id of the upload.
Id of the file in the media of the film.
queued: waiting for the scene; applying: being planned or applied (see stage); applied: the scene was changed; failed: not applied (see failure, retry possible); discarded: cancelled via the API or stopped in mint.
Only for applying: planning, waiting_for_scene (the scene is rendering), applying, rendering.
Only for queued: scene_busy (another change of the scene is running), storyboard_busy (the storyboard is being created), service_unavailable (retried automatically).
Hints for the entry, e.g. timeline_may_be_outdated or scene_changed_since_preview. New values may be added.
Show child attributes
What mint changed (German, as in the mint chat).
Kind of change.
text image layout redraw regenerate noneStoryboard version with the change.
pending: the scene is not rendered yet; done: rendered.
Show child attributes
Reason (for failed and discarded). New codes may be added within v1; treat unknown codes like apply_failed.
English description of the reason.
The text mint shows in the chat (German), if any.
true for failed: POST …/retry is possible.
Only for redraw_required: the current fixed price of redrawing the scene from the mint price list (may change). Retry with allow_redraw: true to accept it.
Who sent the entry: the API access that sent (or last retried) it. Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
Time of the request (UTC).
Last change of the state (UTC).
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 404 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "queued",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": null,
"failure": null,
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:31:02Z"
}
],
"has_more": false,
"next_cursor": null
}Cancels a feedback entry. A queued entry is removed from the queue. An entry being applied is stopped like „Stop“ in the mint chat: the scene gets its previous version back. Answers 200 with the entry (status: discarded, failure.code: cancelled_via_api). 409 feedback_busy (with Retry-After): the entry is being handed over or the change is being written right now; retry shortly. 409 feedback_not_cancellable: the entry is already applied, failed or discarded.
Path parameters
Id of the film (id from POST /films or GET /films).
Id of the feedback entry (id from the feedback object).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body optional
No fields. Send an empty JSON object {} or no body.
Returns
The cancelled entry. Returns the feedback object.
Errors 400 · 401 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
The entry is being handed over or written right now (feedback_busy, with Retry-After), it can no longer be cancelled (feedback_not_cancellable), or a request with this Idempotency-Key is still running (idempotency_in_progress).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/cancel" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/cancel", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/cancel",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={},
)
data = res.json(){
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "discarded",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": null,
"failure": {
"code": "cancelled_via_api",
"message": "The entry was cancelled through the API.",
"app_message": null,
"retry_allowed": false,
"fixed_price_credits": null
},
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:33:40Z"
}Sends a failed feedback entry again (only status: failed, otherwise 409 feedback_not_retryable). The entry is queued again under the calling API access. With allow_redraw: true mint may redraw the scene at a fixed price (see failure.fixed_price_credits of redraw_required). If the company does not have enough credits, the response is 402 insufficient_credits and the entry stays failed. A film cancelled through the API answers 409 film_cancelled.
Path parameters
Id of the film (id from POST /films or GET /films).
Id of the feedback entry (id from the feedback object).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body optional
Change the permission to redraw the scene; without it the previous value applies.
Returns
The entry is queued again (status: queued). Returns the feedback object.
Errors 400 · 401 · 402 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
The company does not have enough credits (insufficient_credits). The entry stays failed; not stored under the Idempotency-Key.
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Only failed entries can be retried (feedback_not_retryable), the film was cancelled through the API (film_cancelled), the entry changed at the same time (feedback_busy, with Retry-After), or a request with this Idempotency-Key is still running (idempotency_in_progress).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/retry" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"allow_redraw": true
}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/retry", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
allow_redraw: true
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/feedback/fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e/retry",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"allow_redraw": True,
},
)
data = res.json(){
"object": "feedback",
"id": "fb_2a7d4c9e1b6f3a8d5c0e7b2f4a9d1c6e",
"batch_id": "fbb_6e1c8a3f5d2b9e4a7c0f1d6b3e8a5c2f",
"film_id": "k7m2xq9v4t8n1b5r3c6d0wza",
"scene": 4,
"at_s": null,
"scene_offset_s": null,
"preview_id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"storyboard_version": 1,
"kind": "text",
"message": "Please write \"customer groups\" instead of \"target groups\" in the headline.",
"region": null,
"point": null,
"attachments": [],
"allow_redraw": false,
"external_ref": "lms-review-8812",
"status": "queued",
"stage": null,
"queue_reason": null,
"warnings": [],
"result": null,
"failure": null,
"sender": {
"kind": "user",
"name": "Anna Schmidt",
"email": "anna.schmidt@example.edu"
},
"created_at": "2026-11-10T08:31:02Z",
"updated_at": "2026-11-10T08:31:02Z"
}Comments belong to a finished film (a rendered revision). They mark a time and optionally a point in the picture, like comments in mint. A comment changes nothing by itself: POST /films/{id}/comments/apply applies the open comments and mint renders a new revision. The approval of the new revision stays with a person in mint.
at_s is the time in the film without the brand intro. If you play the approved file with an intro, subtract its length.
Attributes
commentId of the comment (for comment_ids).
Revision of the film the comment belongs to.
Time in the film in seconds, without the brand intro.
Horizontal position in the picture (0 = left, 1 = right), if given.
Vertical position in the picture (0 = top, 1 = bottom), if given.
Number of the scene at at_s, if known.
Text of the comment.
Who wrote the comment: a user in mint or an API access of your company (name = name of the access, email = null). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
open; in_progress while a new revision is being created from it; applied or not_applied afterwards; resolved if marked as done in mint. New values may be added within v1.
Outcome of applying the comment (null until it was applied).
Show child attributes
Revision that applied the comment.
What mint changed (text from mint, may be German).
Why mint did not apply it, if so (text from mint, may be German).
Show child attributes
Upload the attachment came from, if it was added through the API (POST /uploads); null for attachments added in mint.
Id of the attachment in the mint project (the same file always has the same id).
Creation time (UTC).
Last change (UTC).
{
"object": "comment",
"id": "cmt_9QwX2rLm7Tz",
"revision": 2,
"at_s": 42.5,
"x": 0.62,
"y": 0.31,
"scene": 5,
"message": "The chart should show 2026, not 2025.",
"author": {
"kind": "api",
"name": "Learning platform",
"email": null
},
"status": "open",
"result": null,
"attachments": [
{
"upload_id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"media_id": "md_77120"
}
],
"created_at": "2026-11-11T15:02:19Z",
"updated_at": "2026-11-11T15:02:19Z"
}Adds a comment to the latest finished revision of a film, at a time (at_s) and optionally a point (x, y) in the picture. at_s is the time in the film without the brand intro: if you play the approved file with an intro, subtract the intro length. message has 1–2000 characters. attachments are up to 5 ids of uploads of your company (POST /uploads); each use extends the upload's expiry. Comments are only possible on the latest finished revision: with revision set to an older one, or if a newer revision is finished in the meantime, the answer is 409 revision_locked with details.latest_revision. Without a finished film: 409 film_not_ready. The comment changes nothing by itself; POST /films/{id}/comments/apply applies the open comments as a new revision. A film cancelled through the API (status: cancelled) takes no more comments: 409 film_cancelled.
Path parameters
Id of the film (id from POST /films or GET /films).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body
Time in the film in seconds, without the brand intro.
Optional horizontal position (0–1).
Optional vertical position (0–1).
Text of the comment (trimmed).
Up to 5 upload ids of your company. Unknown ids and uploads of other companies: 400 upload_not_found; expired: 410 upload_expired.
Optional: the revision you commented on. If it is not the latest finished one, the answer is 409 revision_locked.
Returns
The new comment. Returns the comment object.
Errors 400 · 401 · 403 · 404 · 409 · 410 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
revision_locked (details.latest_revision), film_not_ready or film_cancelled (the film was cancelled through the API).
An upload in attachments has expired (upload_expired, field names it).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"at_s": 42.5,
"x": 0.62,
"y": 0.31,
"message": "The chart should show 2026, not 2025.",
"attachments": [
"upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f"
]
}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
at_s: 42.5,
x: 0.62,
y: 0.31,
message: "The chart should show 2026, not 2025.",
attachments: [
"upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f"
]
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"at_s": 42.5,
"x": 0.62,
"y": 0.31,
"message": "The chart should show 2026, not 2025.",
"attachments": ["upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f"],
},
)
data = res.json(){
"object": "comment",
"id": "cmt_9QwX2rLm7Tz",
"revision": 2,
"at_s": 42.5,
"x": 0.62,
"y": 0.31,
"scene": 5,
"message": "The chart should show 2026, not 2025.",
"author": {
"kind": "api",
"name": "Learning platform",
"email": null
},
"status": "open",
"result": null,
"attachments": [
{
"upload_id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"media_id": "md_77120"
}
],
"created_at": "2026-11-11T15:02:19Z",
"updated_at": "2026-11-11T15:02:19Z"
}The comments on a finished film: by default on its latest finished revision, with revision on an earlier one. Sorted by at_s, then id. Comments come from the API and from users in mint; author tells who wrote them (personal data). Paging: pass revision together with cursor; if a newer revision was finished in between, a cursor without revision returns 400 invalid_cursor. 409 film_not_ready if the film has no finished revision yet; an unknown revision returns 404 not_found.
Path parameters
Id of the film (id from POST /films or GET /films).
Query parameters
Revision of the film (default: the latest finished one).
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Returns
One page of comments (limit 1–100).
Show response attributes
listRevision the comments belong to.
Show child attributes
commentId of the comment (for comment_ids).
Revision of the film the comment belongs to.
Time in the film in seconds, without the brand intro.
Horizontal position in the picture (0 = left, 1 = right), if given.
Vertical position in the picture (0 = top, 1 = bottom), if given.
Number of the scene at at_s, if known.
Text of the comment.
Who wrote the comment: a user in mint or an API access of your company (name = name of the access, email = null). Personal data.
Show child attributes
user: a mint user; api: an API access of your company.
Name of the user, or the name of the API access.
E-mail address of the user (lower case), if known; always null for api.
open; in_progress while a new revision is being created from it; applied or not_applied afterwards; resolved if marked as done in mint. New values may be added within v1.
Outcome of applying the comment (null until it was applied).
Show child attributes
Revision that applied the comment.
What mint changed (text from mint, may be German).
Why mint did not apply it, if so (text from mint, may be German).
Show child attributes
Upload the attachment came from, if it was added through the API (POST /uploads); null for attachments added in mint.
Id of the attachment in the mint project (the same file always has the same id).
Creation time (UTC).
Last change (UTC).
Pass as cursor (with the same revision) to get the next page; null on the last page.
Errors 400 · 401 · 403 · 404 · 409 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
The film has no finished revision yet (film_not_ready).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"revision": 2,
"data": [
{
"object": "comment",
"id": "cmt_9QwX2rLm7Tz",
"revision": 2,
"at_s": 42.5,
"x": 0.62,
"y": 0.31,
"scene": 5,
"message": "The chart should show 2026, not 2025.",
"author": {
"kind": "api",
"name": "Learning platform",
"email": null
},
"status": "open",
"result": null,
"attachments": [
{
"upload_id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"media_id": "md_77120"
}
],
"created_at": "2026-11-11T15:02:19Z",
"updated_at": "2026-11-11T15:02:19Z"
}
],
"has_more": false,
"next_cursor": null
}Applies the open comments of the latest finished revision (all, or the ones in comment_ids) as a new revision of the film, like “Apply comments” in mint. Answers 202 with an operation of type film.comments_apply (Location points to /api/v1/operations/{id}). When it has succeeded, result.id is the new revision. The same Idempotency-Key with the same body always returns the same operation, also after 24 hours; a different body returns 422 idempotency_mismatch. Errors before the start leave no operation: 409 film_cancelled (the film was cancelled through the API), 409 film_not_ready (no finished film or the film is being changed), 409 no_open_comments, 409 comments_not_open (details.comment_ids are no longer open), 409 correction_in_progress (a new revision is already being created; details.operation_id if it was started through the API), 409 film_busy (retry after Retry-After seconds), 402 insufficient_credits. Credits are booked like in mint, on the user who ordered the film (requested_by). If mint restarts while the comments are being applied, the operation fails with interrupted_by_restart; the comments are open again and you can apply them again with a new Idempotency-Key. The approval of a film always stays with a person in mint.
Path parameters
Id of the film (id from POST /films or GET /films).
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body optional
Only these comments (all must still be open, otherwise 409 comments_not_open). Without it: all open comments of the latest finished revision.
Returns
The operation that creates the new revision (also for a repeated Idempotency-Key). Returns the operation object.
Location Path of the operation (/api/v1/operations/{id}).Errors 400 · 401 · 402 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not enough credits for the new revision (insufficient_credits). Retry after topping up.
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
film_cancelled (the film was cancelled through the API), film_not_ready, no_open_comments, comments_not_open (details.comment_ids), correction_in_progress or film_busy (with Retry-After).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments/apply" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments/apply", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/comments/apply",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={},
)
data = res.json(){
"object": "operation",
"id": "op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a",
"type": "film.comments_apply",
"status": "queued",
"created_at": "2026-11-11T15:10:00Z",
"updated_at": "2026-11-11T15:10:00Z",
"result": null,
"error": null
}Uploads bring your own images and videos into mint, for example a screenshot as an attachment of feedback or a comment. Send the raw bytes with the matching Content-Type. Uploads are free, belong to your company and expire 7 days after the last use. The file itself cannot be downloaded through the API.
Attributes
uploadId of the upload; use it in attachments.
Cleaned name of the file (display only).
Media type of the stored file (the real type of the content).
image/png image/jpeg image/webp video/mp4 video/quicktime video/webmSize in bytes.
SHA-256 of the file (hex).
Time of the first upload (UTC).
Expiry (UTC): 7 days after creation or the last use.
{
"object": "upload",
"id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"filename": "screenshot-scene-4.png",
"content_type": "image/png",
"bytes": 284113,
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"created_at": "2026-11-10T08:30:12Z",
"expires_at": "2026-11-17T08:30:12Z"
}Uploads an image or a video for your company, to be used as an attachment of comments (attachments of POST /films/{id}/comments). Send the bytes of the file as the request body with its media type as Content-Type (image/png, image/jpeg, image/webp, video/mp4, video/quicktime, video/webm; no SVG) and a Content-Length (required; chunked uploads are rejected with 411 length_required). Images may be at most 25 MB, videos at most 200 MB. mint checks the content: if it does not match the media type, the answer is 415 file_content_mismatch. An image of another allowed type (for example a JPEG sent as image/png) is stored with its real type; content_type of the answer shows it. Uploading the same file (same bytes and type) again returns the existing upload with 200 and extends its expiry; a new upload returns 201. An upload expires 7 days after it was created or last used. Every API access of your company can use every upload of the company; other companies never see it. The file itself cannot be downloaded through the API. At most 2 uploads run at the same time per mint server: more return 429 rate_limited with details.reason parallel_uploads and Retry-After: 5. Each company has a storage quota for active uploads (409 upload_quota_exceeded with details.quota_bytes). A slow upload is aborted after 5 minutes (503). Uploads are free of credits.
Query parameters
Name of the file for display (control characters are removed, at most 160 characters). It is never used as a path.
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body
The bytes of the file.
Content types: image/png image/jpeg image/webp video/mp4 video/quicktime video/webm
Returns
The same file was uploaded before: the existing upload (expiry extended). Returns the upload object.
Location Path of the upload (/api/v1/uploads/{id}).The new upload. Returns the upload object.
Location Path of the upload (/api/v1/uploads/{id}).Errors 400 · 401 · 403 · 409 · 411 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
The upload storage of your company is full (upload_quota_exceeded, details.quota_bytes).
Content-Length is missing (length_required).
The file is too large for its type (payload_too_large, details.max_bytes).
Media type not allowed (unsupported_media_type) or content does not match it (file_content_mismatch).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests or uploads at the same time (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/uploads?filename=screenshot-scene-4.png" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: image/png" \
--data-binary @screenshot-scene-4.pngimport { readFile } from "node:fs/promises";
const res = await fetch("https://api.cream-ai.de/api/v1/uploads?filename=screenshot-scene-4.png", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "image/png",
},
body: await readFile("screenshot-scene-4.png"),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/uploads",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "image/png",
},
params={
"filename": "screenshot-scene-4.png",
},
data=open("screenshot-scene-4.png", "rb"),
)
data = res.json(){
"object": "upload",
"id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"filename": "screenshot-scene-4.png",
"content_type": "image/png",
"bytes": 284113,
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"created_at": "2026-11-10T08:30:12Z",
"expires_at": "2026-11-17T08:30:12Z"
}The metadata of an upload of your company (never the file). Uploads of other companies and unknown ids return 404 not_found; expired uploads 410 upload_expired.
Path parameters
Id of the upload (id from POST /uploads).
Returns
The upload. Returns the upload object.
Errors 401 · 403 · 404 · 410 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
The upload has expired (upload_expired). Upload the file again.
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/uploads/upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/uploads/upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/uploads/upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "upload",
"id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
"filename": "screenshot-scene-4.png",
"content_type": "image/png",
"bytes": 284113,
"sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"created_at": "2026-11-10T08:30:12Z",
"expires_at": "2026-11-17T08:30:12Z"
}Operations represent work that takes longer than one request, such as creating a storyboard preview or applying comments. See Long-running operations.
Attributes
operationKind of operation. New types may be added within v1; ignore operations of unknown types.
storyboard.preview film.comments_applyqueued running succeeded failedCreation time (UTC).
Last change (UTC).
Show child attributes
Show child attributes
{
"object": "operation",
"id": "op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a",
"type": "storyboard.preview",
"status": "succeeded",
"created_at": "2026-11-10T08:25:00Z",
"updated_at": "2026-11-10T08:27:41Z",
"result": {
"object": "storyboard_preview",
"id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview?preview_id=pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d"
},
"error": null
}The current state of a long-running operation of your company, for example a storyboard preview (storyboard.preview) or applying comments to a finished film (film.comments_apply). The Location header of the request that started it points here. Poll until status is succeeded or failed (every few seconds is enough); the state is computed when you read it. result is set when the operation succeeded: storyboard_preview with the URL of the preview, or film_revision with the new revision (for example V3) and the URL of the film. error is set when it failed. Error codes: start_failed, preview_failed, correction_failed, interrupted_by_restart. start_failed: the operation could not be started; send the request again with a new Idempotency-Key. interrupted_by_restart: mint was restarted while applying the comments; they are open again and can be applied again. The scopes depend on the type (storyboard.preview: films:read + previews:read; film.comments_apply: films:read + films:revise; films:revise includes films:read). A key without them gets 403 forbidden_scope with details.required_scopes. Unknown ids, operations of other companies and operations of films deleted in mint return 404 not_found, before scopes are checked. New operation types may be added within v1; ignore operations of types you do not know.
Path parameters
Id of the operation (id of the Operation object, also at the end of the Location header).
Returns
The operation. Returns the operation object.
Errors 401 · 403 · 404 · 429 · 500 · 503
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled). With forbidden_scope the key lacks a scope for this type of operation; details.required_scopes lists all scopes the type needs.
The operation was not found (not_found): unknown id, an operation of another company or of a film deleted in mint.
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/operations/op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/operations/op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/operations/op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "operation",
"id": "op_4d9b2e7a1c6f3d8b5e0a2c7f9b4d1e6a",
"type": "storyboard.preview",
"status": "succeeded",
"created_at": "2026-11-10T08:25:00Z",
"updated_at": "2026-11-10T08:27:41Z",
"result": {
"object": "storyboard_preview",
"id": "pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d",
"url": "https://api.cream-ai.de/api/v1/films/k7m2xq9v4t8n1b5r3c6d0wza/storyboard-preview?preview_id=pv_8c1e4a7d2b5f9e3c6a0d1b4e7f2a5c8d"
},
"error": null
}Categories sort films in mint, in two levels: categories and subcategories. Link them to your own structure with external_key, for example a course code, and use that key when you order a film (category.external_key). Creating a category with an external_key that already exists returns the existing category.
Attributes
categoryId of the category in mint.
Name, unique (case-insensitive) on its level.
Id of the top-level category of a subcategory; null for top-level categories.
Key of the connected system (e.g. a module number); null if not set.
Projects assigned directly to this category (not counting subcategories). Only with include=project_count.
Subcategories of a top-level category; always empty for subcategories.
{
"object": "category",
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"parent_id": null,
"external_key": "MKT",
"project_count": 12,
"children": []
}Returns the categories of the company as a tree: top-level categories with their subcategories in children. Categories are a bounded two-level tree, so there is no paging (has_more is always false). With external_key only the category with this key is returned (zero or one entry, on any level). With include=project_count every category carries project_count; this loads all projects of the company and counts as a write request for the rate limits. The list is cached per company for up to 30 seconds, so changes made in mint (and on other servers) can take up to 30 seconds to appear; project_count values can be up to 30 seconds old.
Query parameters
Only the category with this external key (exact match, case-sensitive).
Comma-separated extras. Allowed: project_count.
Returns
The category tree (or the category with the requested external key).
Show response attributes
listShow child attributes
categoryId of the category in mint.
Name, unique (case-insensitive) on its level.
Id of the top-level category of a subcategory; null for top-level categories.
Key of the connected system (e.g. a module number); null if not set.
Projects assigned directly to this category (not counting subcategories). Only with include=project_count.
Subcategories of a top-level category; always empty for subcategories.
Always false: the category tree is returned completely.
Always null (no paging).
Errors 400 · 401 · 403 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/categories" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/categories", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/categories",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "category",
"id": "mk7t2q9x4v1n",
"name": "Marketing",
"parent_id": null,
"external_key": "MKT",
"children": [
{
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"parent_id": "mk7t2q9x4v1n",
"external_key": "MKT101",
"children": []
}
]
}
],
"has_more": false,
"next_cursor": null
}Creates a top-level category, or a subcategory with parent_id (only two levels). With external_key the request is safe to repeat: if a category with this key already exists (on any level, even with another parent_id), the response is 200 with that category and nothing is changed. The same name on the same level returns 409 category_exists with details.category_id. A company can have at most 500 categories (main and subcategories together); creating one more returns 409 category_limit_reached with details.limit.
Headers
Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
Request body
Name of the new category (trimmed; at most 80 characters, longer names are rejected).
Id of a top-level category to create a subcategory; omit or null for a top-level category.
Optional key of the connected system. Repeating the request with the same key returns the existing category (200).
Returns
A category with this external key already exists; it is returned unchanged. Returns the category object.
The category was created. Returns the category object.
Errors 400 · 401 · 403 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Conflict (category_exists, external_key_exists, external_key_conflict, category_limit_reached, idempotency_in_progress, version_conflict, previous_version_creating, film_deleted, not_cancellable, file_unavailable, storyboard_not_ready, storyboard_not_current, timeline_outdated, preview_in_progress, preview_not_ready, preview_unsupported, feedback_queue_full, feedback_not_cancellable, feedback_not_retryable, feedback_busy, revision_locked, film_not_ready, film_busy, no_open_comments, comments_not_open, correction_in_progress, upload_quota_exceeded, film_cancelled).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X POST "https://api.cream-ai.de/api/v1/categories" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "MKT101 Marketing basics",
"parent_id": "mk7t2q9x4v1n",
"external_key": "MKT101"
}'const res = await fetch("https://api.cream-ai.de/api/v1/categories", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "MKT101 Marketing basics",
parent_id: "mk7t2q9x4v1n",
external_key: "MKT101"
}),
});
const data = await res.json();import os, uuid
import requests
res = requests.post(
"https://api.cream-ai.de/api/v1/categories",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"name": "MKT101 Marketing basics",
"parent_id": "mk7t2q9x4v1n",
"external_key": "MKT101",
},
)
data = res.json(){
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing basics",
"parent_id": "mk7t2q9x4v1n",
"external_key": "MKT101",
"children": []
}Changes name and/or external_key (at least one). external_key: null removes the key. Moving a category (parent_id) is not supported in v1. A key used by another category returns 409 external_key_exists with details.category_id. If another request changed the same field of this category at the same time, the response is 503 service_unavailable with Retry-After; repeat the request.
Path parameters
Id of the category.
Headers
Optional unique key of this write request (1–128 visible ASCII characters). Retries with the same key return the stored response.
Request body
New name.
New external key; null removes it.
Returns
The updated category. Returns the category object.
Errors 400 · 401 · 403 · 404 · 409 · 413 · 415 · 422 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Conflict (category_exists, external_key_exists, external_key_conflict, category_limit_reached, idempotency_in_progress, version_conflict, previous_version_creating, film_deleted, not_cancellable, file_unavailable, storyboard_not_ready, storyboard_not_current, timeline_outdated, preview_in_progress, preview_not_ready, preview_unsupported, feedback_queue_full, feedback_not_cancellable, feedback_not_retryable, feedback_busy, revision_locked, film_not_ready, film_busy, no_open_comments, comments_not_open, correction_in_progress, upload_quota_exceeded, film_cancelled).
Request body too large (payload_too_large).
Request body is not JSON (unsupported_media_type).
Idempotency-Key reused with a different request (idempotency_mismatch).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl -X PATCH "https://api.cream-ai.de/api/v1/categories/rz3p8w1d6c0b" \
-H "Authorization: Bearer $MINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "MKT101 Marketing – basics"
}'const res = await fetch("https://api.cream-ai.de/api/v1/categories/rz3p8w1d6c0b", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "MKT101 Marketing – basics"
}),
});
const data = await res.json();import os
import requests
res = requests.patch(
"https://api.cream-ai.de/api/v1/categories/rz3p8w1d6c0b",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
json={
"name": "MKT101 Marketing – basics",
},
)
data = res.json(){
"object": "category",
"id": "rz3p8w1d6c0b",
"name": "MKT101 Marketing – basics",
"parent_id": "mk7t2q9x4v1n",
"external_key": "MKT101",
"children": []
}Briefing templates are created by people in mint. A template fixes the look and the production settings of a film, so an order only needs the content. Use the key as template in POST /films.
Attributes
templateId of the template in mint.
Key of the template, unique in the company. Use it as template in POST /films.
Language the template sets, or null if it does not set one.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgValues the template sets, with the names and values of settings in POST /films. Fields the template does not set are missing.
Show child attributes
Aspect ratio. Missing if the template does not set it.
16x9 9x16 1x1Id of the style. Missing if the template does not set it.
Brand, or null for no brand. Missing: mint chooses the brand automatically.
Voice, or null for the automatic voice. Missing if the template does not set it.
How the text is spoken. Missing if the template does not set it.
verbatim smooth freePace of the film. Missing if the template does not set it.
presenting lively kineticCreative freedom in percent. Missing if the template does not set it.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds). Templates in mint allow up to 60 minutes; POST /films accepts at most 900 seconds in settings. Missing if the template does not set it.
Last change of the template (UTC).
{
"object": "template",
"id": "tpl_51",
"key": "lesson-standard",
"name": "Lesson – standard",
"language": "de",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"updated_at": "2026-10-30T16:20:00Z"
}Active briefing templates of the company, created by people in mint. Use the key as template in POST /films. settings shows only the template values that POST /films also accepts in settings; the template may set further mint settings (for example music, depth or audience), which apply as well. Sorted by name (without case), then key. Changes in mint appear immediately.
Query parameters
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Returns
One page of the list.
Show response attributes
listShow child attributes
templateId of the template in mint.
Key of the template, unique in the company. Use it as template in POST /films.
Language the template sets, or null if it does not set one.
de en fr es it pt nl pl cs sk hu ro hr sl sv da no fi tr id vi el uk ru bgValues the template sets, with the names and values of settings in POST /films. Fields the template does not set are missing.
Show child attributes
Aspect ratio. Missing if the template does not set it.
16x9 9x16 1x1Id of the style. Missing if the template does not set it.
Brand, or null for no brand. Missing: mint chooses the brand automatically.
Voice, or null for the automatic voice. Missing if the template does not set it.
How the text is spoken. Missing if the template does not set it.
verbatim smooth freePace of the film. Missing if the template does not set it.
presenting lively kineticCreative freedom in percent. Missing if the template does not set it.
0 25 40 65 100Target duration in seconds (in steps of 6 seconds). Templates in mint allow up to 60 minutes; POST /films accepts at most 900 seconds in settings. Missing if the template does not set it.
Last change of the template (UTC).
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 404 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/templates" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/templates", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/templates",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "template",
"id": "tpl_51",
"key": "lesson-standard",
"name": "Lesson – standard",
"language": "de",
"settings": {
"format": "16x9",
"style_id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"brand_id": "brand-northwind-x7k2p9",
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"narration_mode": "verbatim",
"tempo": "presenting",
"freedom": 40,
"video_share": 25,
"target_duration_s": 180
},
"updated_at": "2026-10-30T16:20:00Z"
}
],
"has_more": false,
"next_cursor": null
}Styles define the visual look of a film. The API lists the styles your company may use in their approved revision: its own styles, styles shared with it and global styles. Use the id as settings.style_id in POST /films.
Attributes
styleStyle id in mint.
organization: style of a company; global: style available to all companies.
own: style of this company; shared: style of another company shared with this one; global: global style.
Approved revision of the style.
Time of the approval (UTC); null if unknown.
Last change of the style (UTC).
{
"object": "style",
"id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"slug": "lecture-clean",
"name": "Lecture – clean",
"visibility": "organization",
"access": "own",
"approved_revision": 4,
"approved_at": "2026-10-29T09:45:12Z",
"updated_at": "2026-10-29T09:45:12Z"
}Approved editorial styles the company can use for films: its own styles, styles shared with it and global styles, each in its approved revision. Sorted by updated_at (newest first), then id. Changes made in mint may take up to 30 seconds to appear.
Query parameters
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Returns
One page of the list.
Show response attributes
listShow child attributes
styleStyle id in mint.
organization: style of a company; global: style available to all companies.
own: style of this company; shared: style of another company shared with this one; global: global style.
Approved revision of the style.
Time of the approval (UTC); null if unknown.
Last change of the style (UTC).
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 404 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Not found (not_found).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/styles" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/styles", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/styles",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "style",
"id": "b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45",
"slug": "lecture-clean",
"name": "Lecture – clean",
"visibility": "organization",
"access": "own",
"approved_revision": 4,
"approved_at": "2026-10-29T09:45:12Z",
"updated_at": "2026-10-29T09:45:12Z"
}
],
"has_more": false,
"next_cursor": null
}Brands hold the corporate design of your company: styles, voices and more. Use the id as settings.brand_id in POST /films.
Attributes
brandBrand id in mint.
active draftIds of the editorial styles linked to this brand. Use GET /styles for the styles that are approved.
Show child attributes
Voice id at the voice provider.
Language code, e.g. de.
Default voice of the brand for this language.
Creation time (UTC).
Last change (UTC).
{
"object": "brand",
"id": "brand-northwind-x7k2p9",
"slug": "northwind",
"name": "Northwind University",
"description": "Corporate design for all course films.",
"status": "active",
"style_ids": [
"b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45"
],
"voices": [
{
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"name": "Clara",
"language": "de",
"default": true
}
],
"created_at": "2026-09-14T10:02:44Z",
"updated_at": "2026-10-21T12:52:17Z"
}Brands of the company with their linked styles and voices (no asset URLs). Sorted by name, then id. Changes made in mint may take up to 30 seconds to appear.
Query parameters
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Returns
One page of the list.
Show response attributes
listShow child attributes
brandBrand id in mint.
active draftIds of the editorial styles linked to this brand. Use GET /styles for the styles that are approved.
Show child attributes
Voice id at the voice provider.
Language code, e.g. de.
Default voice of the brand for this language.
Creation time (UTC).
Last change (UTC).
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/brands" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/brands", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/brands",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "brand",
"id": "brand-northwind-x7k2p9",
"slug": "northwind",
"name": "Northwind University",
"description": "Corporate design for all course films.",
"status": "active",
"style_ids": [
"b6ed57e1-2c4f-4b8a-9d3e-6f1a0c2b7e45"
],
"voices": [
{
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"name": "Clara",
"language": "de",
"default": true
}
],
"created_at": "2026-09-14T10:02:44Z",
"updated_at": "2026-10-21T12:52:17Z"
}
],
"has_more": false,
"next_cursor": null
}Voices speak the narration. Use the id as settings.voice_id in POST /films, or leave it to the template.
Attributes
voiceVoice id at the voice provider. The same voice appears once per language.
Language code, e.g. de.
elevenlabsBrands that use this voice for this language, sorted by brand_id.
Show child attributes
Default voice of this brand for this language.
{
"object": "voice",
"id": "Xb7hH8MSUJpSbSDYk0k2",
"name": "Clara",
"language": "de",
"provider": "elevenlabs",
"brands": [
{
"brand_id": "brand-northwind-x7k2p9",
"default": true
}
]
}Voices of all brands of the company, one entry per voice and language. Sorted by name, then id. Changes made in mint may take up to 30 seconds to appear.
Query parameters
Page size (1–100).
50 · 1–100Opaque cursor from next_cursor of the previous page.
Only voices of this language (language code, e.g. de).
Returns
One page of the list.
Show response attributes
listShow child attributes
voiceVoice id at the voice provider. The same voice appears once per language.
Language code, e.g. de.
elevenlabsBrands that use this voice for this language, sorted by brand_id.
Show child attributes
Default voice of this brand for this language.
Pass as cursor to get the next page; null on the last page.
Errors 400 · 401 · 403 · 429 · 500 · 503
Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
Missing, malformed, revoked or expired API key (unauthorized).
Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
Too many requests (rate_limited).
Internal error (internal). Quote the request id when you contact support.
Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).
curl "https://api.cream-ai.de/api/v1/voices?language=de" \
-H "Authorization: Bearer $MINT_API_KEY"const res = await fetch("https://api.cream-ai.de/api/v1/voices?language=de", {
headers: {
Authorization: `Bearer ${process.env.MINT_API_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://api.cream-ai.de/api/v1/voices",
headers={
"Authorization": f"Bearer {os.environ['MINT_API_KEY']}",
},
params={
"language": "de",
},
)
data = res.json(){
"object": "list",
"data": [
{
"object": "voice",
"id": "Xb7hH8MSUJpSbSDYk0k2",
"name": "Clara",
"language": "de",
"provider": "elevenlabs",
"brands": [
{
"brand_id": "brand-northwind-x7k2p9",
"default": true
}
]
}
],
"has_more": false,
"next_cursor": null
}